[Java] 프로그래머스 보석 쇼핑

hyunnzl·2025년 4월 3일

프로그래머스

목록 보기
19/58
post-thumbnail

https://school.programmers.co.kr/learn/courses/30/lessons/67258

난이도

Level 3

문제

개발자 출신으로 세계 최고의 갑부가 된 어피치는 스트레스를 받을 때면 이를 풀기 위해 오프라인 매장에 쇼핑을 하러 가곤 합니다.
어피치는 쇼핑을 할 때면 매장 진열대의 특정 범위의 물건들을 모두 싹쓸이 구매하는 습관이 있습니다.
어느 날 스트레스를 풀기 위해 보석 매장에 쇼핑을 하러 간 어피치는 이전처럼 진열대의 특정 범위의 보석을 모두 구매하되 특별히 아래 목적을 달성하고 싶었습니다.

진열된 모든 종류의 보석을 적어도 1개 이상 포함하는 가장 짧은 구간을 찾아서 구매

진열대의 3번부터 7번까지 5개의 보석을 구매하면 모든 종류의 보석을 적어도 하나 이상씩 포함하게 됩니다.

진열대의 3, 4, 6, 7번의 보석만 구매하는 것은 중간에 특정 구간(5번)이 빠지게 되므로 어피치의 쇼핑 습관에 맞지 않습니다.

진열대 번호 순서대로 보석들의 이름이 저장된 배열 gems가 매개변수로 주어집니다. 이때 모든 보석을 하나 이상 포함하는 가장 짧은 구간을 찾아서 return 하도록 solution 함수를 완성해주세요.
가장 짧은 구간의 시작 진열대 번호와 끝 진열대 번호를 차례대로 배열에 담아서 return 하도록 하며, 만약 가장 짧은 구간이 여러 개라면 시작 진열대 번호가 가장 작은 구간을 return 합니다.

내 코드

import java.util.*;

class Solution {
    public int[] solution(String[] gems) {
        
        int kind = new HashSet<>(Arrays.asList(gems)).size();
        int[] answer = new int[2];
        
        int length = Integer.MAX_VALUE;
        int start = 0;
        
        Map<String, Integer> map = new HashMap<>();
        
        for(int end = 0; end < gems.length; end++){
            map.put(gems[end], map.getOrDefault(gems[end], 0) + 1);
            
            while(map.get(gems[start]) > 1){
                map.put(gems[start], map.get(gems[start]) - 1);
                start++;
            }
            
            if(kind == map.size() && length > (end - start)){
                length = end - start;
                answer[0] = start + 1;
                answer[1] = end + 1;
            }
        }
        
        return answer;
    }
}

시간초과 때문에 다른 사람의 코드를 참고했다.

코드 설명 - 보석 쇼핑 문제 (투 포인터 + 해시맵)
이 코드는 모든 종류의 보석을 최소 범위 내에서 포함하는 구간을 찾는 문제를 해결한다.
gems 배열에는 보석들의 이름이 순서대로 주어지며, 이 중 모든 종류의 보석을 포함하는 가장 짧은 연속된 구간의 시작과 끝 인덱스를 찾아 반환한다.

✅ 핵심 알고리즘: 투 포인터 + 해시맵

  • startend 두 포인터를 사용하여 윈도우(구간)를 설정합니다.
  • map은 현재 윈도우 내의 보석들의 개수를 저장합니다.
  • kind는 전체 보석의 종류 수입니다 (Set을 이용해 계산).

✅ 동작 과정

  • 모든 보석 종류 수(kind)를 먼저 구한다.
  • end 포인터를 오른쪽으로 이동하면서 map에 보석을 추가한다.
  • map에 저장된 보석 중 start 포인터가 가리키는 보석의 수가 1개 초과라면, 해당 보석을 하나 줄이고 start를 오른쪽으로 이동시켜 윈도우를 좁힌다.
  • 현재 map에 있는 보석 종류 수가 전체 종류 수와 같고, 구간의 길이가 지금까지 찾은 최소 길이보다 짧다면 결과를 갱신한다.
  • 마지막으로 가장 짧은 구간의 시작과 끝 인덱스를 반환한다 (문제에서 1-based index를 요구하므로 +1을 더함).

0개의 댓글