Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++로 k개의 정렬된 배열에서 m번째로 작은 값 찾는 방법

이 문제에서는 크기가 서로 다른 k개의 정렬된 배열이 주어지며, 이 배열들을 합쳤을 때의 m번째로 작은 값을 찾아야 합니다.

문제 설명

k개의 정렬된 배열을 하나로 병합한 배열을 만들었을 때, 그 배열에서 m번째로 작은 원소를 구하는 것이 목표입니다.

예제로 문제 이해하기

입력:

m = 4
arr[][] = { {4, 7},
            {2, 5, 6},
            {3, 9, 12, 15, 19} }

출력: 5

설명: 모든 배열을 병합하고 정렬하면 다음과 같습니다.

2, 3, 4, 5, 6, 7, 9, 12, 15, 19

이 정렬된 배열에서 4번째 원소는 5입니다.

해결 접근 방법

1. 단순한 방법 — 병합 후 정렬

가장 간단한 방법은 모든 배열의 원소를 하나의 배열에 병합한 뒤 오름차순으로 정렬하는 것입니다. 정렬이 완료되면 인덱스 (m-1) 위치의 값이 곧 m번째로 작은 원소가 됩니다.

다만 이 방법은 전체 원소를 모두 저장하고 정렬해야 하므로 시간 복잡도와 공간 복잡도 측면에서 비효율적입니다.

2. 효율적인 방법 — 최소 힙(Min Heap) 활용

더 효율적인 해결책은 최소 힙(Min Heap) 자료구조를 사용하는 것입니다. 동작 과정은 다음과 같습니다.

  1. 각 배열의 첫 번째 원소를 최소 힙에 삽입합니다. 이때 어떤 배열의 몇 번째 원소인지를 함께 저장합니다.
  2. 힙에서 가장 작은 원소를 꺼내고(pop), 해당 원소가 속한 배열의 다음 원소를 힙에 삽입합니다.
  3. 위 과정을 m번 반복합니다.
  4. m번째로 꺼낸 값이 바로 우리가 찾는 답입니다.

이 방식은 실제로 배열을 병합하지 않고도 필요한 만큼(m개)만 처리하므로 훨씬 효율적입니다. 시간 복잡도는 O(m log k)가 됩니다.

C++ 구현 예제

#include <bits/stdc++.h>
using namespace std;

typedef pair<int, pair<int, int> > ppi;

int findMSmallestElement(vector<vector<int> > sortedArr, int m) {
    priority_queue<ppi, vector<ppi>, greater<ppi> > priorQueue;

    // 각 배열의 첫 번째 원소를 힙에 삽입
    for (int i = 0; i < sortedArr.size(); i++)
        priorQueue.push({ sortedArr[i][0], { i, 0 } });

    int count = 0;
    int i = 0, j = 0;
    while (count < m && priorQueue.empty() == false) {
        ppi curr = priorQueue.top();
        priorQueue.pop();
        i = curr.second.first;
        j = curr.second.second;
        // 같은 배열의 다음 원소를 힙에 추가
        if (j + 1 < sortedArr[i].size())
            priorQueue.push({ sortedArr[i][j + 1], { i, (j + 1) } });
        count++;
    }
    return sortedArr[i][j];
}

int main() {
    vector<vector<int> > arr{ {4 , 7},
                              {2, 5, 6},
                              {3, 9, 12, 15, 19}};
    int m = 6;
    cout<<m<<"th smallest value in k sorted arrays is "<<findMSmallestElement(arr, m);

    return 0;
}

실행 결과

6th smallest value in k sorted arrays is 7

마무리

k개의 정렬된 배열에서 m번째로 작은 값을 구할 때, 단순 병합·정렬 방식보다는 최소 힙을 활용한 방법이 효율성 면에서 큰 이점을 제공합니다. 특히 배열의 개수나 원소 개수가 많을 때 이 방법의 장점이 더욱 두드러집니다.