문제 풀이/프로그래머스

프로그래머스 - 보석 쇼핑 [C++]

JJJaewon 2023. 9. 7. 12:04
반응형

 이 문제는 투 포인터와 맵을 이용해서 풀었다. gems 배열의 최대 크기가 100,000 이므로 O(n) 시간 이내의 알고리즘을 구상해야 한다. 구간에 대한 정답을 도출해야 하므로 투 포인터를 떠올렸고, 개수에 상관없이 종류가 모두 들어가야하므로 맵을 떠올렸다.

 

 

 일단 투 포인터를 사용하는 방식에는 한쪽에서 모두 시작하는 것과 양쪽에서 서로 시작하는 것이 있는데, 최소 구간이 같을 경우 시작 진열대 번호가 같아야하므로 왼쪽에서 모두 시작하는 쪽이 더 직관적이라고 생각했다. 처음에는 구간을 찾고 모든 보석의 종류가 들어있는지를 확인하기 위해 mp을 순회하면서 개수를 세는 쪽으로 하려 했으나, 이 방식은 시간 초과가 날 것이다. 만약 입력 배열이 10만이고 각 원소가 모두 다른 보석이라면, 10만 * 10만의 연산을 하기 때문이다.

 그래서 두번째 방식으로 mp의 size를 통해 계산하는 방법을 생각했다. 이를 위해서는 left가 옮겨갈 때 mp의 카운트가 0이 되면 그 요소를 맵에서 제거해줘야 한다. 맵의 find 연산과 erase 연산이 O(log n) 시간만 되어준다면 시간 초과가 나지 않을 것이라 생각했고, 실제로 시간 초과가 나지 않고 정답을 도출할 수 있었다.

 

 

#include <string>
#include <vector>
#include <map>
#include <algorithm>

using namespace std;

vector<int> solution(vector<string> gems) {
    vector<int> answer;
    
    map<string, int> tempCnt;
    
    for (string& gem : gems) {
        tempCnt[gem]++;
    }
    
    int allSize = tempCnt.size();
    int size = gems.size();
    
    map<string, int> mp;
    
    int left = 0;
    int right = 0;
    mp[gems[left]]++;
    int answerLeft = 0;
    int answerRight = size;
    
    while (left <= right && right < size) {
        if (allSize == mp.size()) { // 만족하는 경우
            int range = right - left + 1;
            
            if (range < answerRight - answerLeft + 1) {
                answerLeft = left;
                answerRight = right;
            }
            else if (range == answerRight - answerLeft + 1) {
                answerLeft = min(answerLeft, left);
                answerRight = min(answerRight, right);
            }
            
            mp[gems[left]]--;
            if (mp[gems[left]] == 0) {
                auto it = mp.find(gems[left]);
                mp.erase(it);
            }
            left++;
            
            continue;
        }
        
        // 만족하지 않는 경우
        right++;
        if (right < size) {
            mp[gems[right]]++;
        }
    }
    
    answer.push_back(answerLeft + 1);
    answer.push_back(answerRight + 1);
    
    return answer;
}
반응형