본문 바로가기

알고리즘/HackerRank

[HackerRank] Deque-STL

https://www.hackerrank.com/challenges/deque-stl/problem

 

Deque-STL | HackerRank

Learn to use deque container. Find the maximum number in each and every contiguous sub array of size K in the given array.

www.hackerrank.com

문제 풀이)

 

총 원소의 개수와 한 묶음의 원소의 개수가 주어질 때, 각 묶음에서 가장 큰 수들을 찾아 순서대로 출력해주는 문제이다.

 

Input & Output

 

5 2

3 4 6 3 4

 

5개의 원소 중, 2개씩 묶으므로 {3, 4} {4, 6} {6, 3} {3, 4} 로 총 4개의 묶음이 나오고 각 묶음에서 가장 큰 수를 뽑아내면

 

4, 6, 6, 4 가 된다.

 

단순하게 n개의 원소(출발원소)에 대해서 묶음의 개수만큼 for문을 돌려 최대값을 찾아가는 것은 시간 초과가 난다.

 

따라서 for문이 덜 돌 수 있도록 조정을 해주어야 한다.

 

먼저 가장 단순하게 조정할 수 있는 것은 n개의 원소에 대해서 모두 조사하는 것이 아니라 n - k까지, 즉 마지막 묶음의

 

첫 원소까지만 for문을 돌려주는 것이다.

 

그 다음은 최대값을 찾는 for문을 줄여주는 것이다. 계속 묶음의 개수만큼 for문을 돌리는 것이 아니라, 최대 값을

 

가리키는 인덱스 이전은 무시해주는 것이다.

 

 

아래는 샘플로 주어지는 두 번째 Input이다.

3 4 5 8 1 4 10

첫 번째 묶음에서 가장 큰 수는 '8'이다.

3 4 5 8

그 다음 묶음은 아래와 같다.

4 5 8 1

4와 5는 이미 최대값 8보다 작은 것을 알고 있으므로 더 이상 고려해줄 필요가 없고, 새로들어온 1과 비교해주면 된다.

 

만약 새로 들어온 수와 비교했을 때 최대 값이 바뀌지 않았다면 start를 1 증가시켜준다. 이 의미는 새로 들어온 수

 

또한 최대값보다 작으므로 탐색 범위에서 제외시켜주는 것이다.

 

이러한 과정을 반복하다 만약 최대 값을 가리키는 인덱스가 묶음의 시작 원소보다 작아진다면, 즉 최대 값이 더이상

 

묶음에 포함되지 않는 경우엔 묶음의 첫 번째 원소부터 시작하여 최대 값을 다시 구해준다.

 

역순으로 데이터가 주어질 경우 최악 O(n^2)로 보인다. 사실 데이터들이 모두 역순으로 주어지면 시간 초과가 나오지

 

않을까 싶은데.. 분명 더 효율적인 방법이 있을 거라고 생각한다.

 

< 소스 코드 >

#include <iostream>
#include <deque> 
using namespace std;

void printKMax(int arr[], int n, int k) {
	// deque<int> dq;
	int start = 0;
	int nMaxIndex = 0;

	for (int i = 0; i <= n - k; ++i)
	{
		if (nMaxIndex < i) start = nMaxIndex = i;
		for (int j = start + 1; j < i + k; ++j)
		{
			if (arr[nMaxIndex] < arr[j])
				nMaxIndex = j;
		}
		if (start < nMaxIndex) start = nMaxIndex;
		else start++;

		cout << arr[nMaxIndex] << " ";
	}
	cout << '\n';
}

int main() {
	int t;
	cin >> t;
	while (t>0) {
		int n, k;
		cin >> n >> k;
		int i;
		int arr[n];
		for (i = 0; i<n; i++)
			cin >> arr[i];
		printKMax(arr, n, k);
		t--;
	}
	return 0;
}

< Discussions에서 본 코드 >

void printKMax(int arr[], int n, int k) 
{ 
    std::deque<int> Qi(k); 
    int i; 
    for (i = 0; i < k; ++i) { 
        while ((!Qi.empty()) && arr[i] >= arr[Qi.back()]) 
            Qi.pop_back();
        Qi.push_back(i); 
    } 

    for (; i < n; ++i) { 
        cout << arr[Qi.front()] << " "; 
  
        if ((!Qi.empty()) && Qi.front() <= i - k) 
            Qi.pop_front(); 
  
        while ((!Qi.empty()) && arr[i] >= arr[Qi.back()]) 
            Qi.pop_back();  
        
        Qi.push_back(i); 
    } 
    cout << arr[Qi.front()] << endl;
} 

내 코드는 maxIndex를 잃어버린 시점에서 다시 maxIndex를 찾는 수행이 필요하지만 위의 코드는 deque에서

 

maxIndex가 내림차순으로 정렬되므로, 다시 구해주지 않아도 front가 계속 maxIndex가 된다.

 

'알고리즘 > HackerRank' 카테고리의 다른 글

[HackerRank] Array Manipulation  (0) 2019.06.10
[HackerRank] Attribute Parser  (0) 2019.06.04
[ HackerRank] Attending Workshops  (0) 2019.06.01
[HackerRank] Bit Array  (1) 2019.05.31
[HackerRank] C++ Variadics  (0) 2019.05.31