본문 바로가기
2025/Solving

PGMRS_퍼즐 게임 챌린지(PCCP 기출, JAVA)

by 껐다 켜보셨어요? 2025. 4. 25.

 

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

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

이 문제는 사실 단순하게 풀려면 아래와 같은 풀이로도 가능한데

class Solution {
    static int[] diffs, times;
    static long limit;
    
    public int solution(int[] diffs, int[] times, long limit) {
        // 할당
        this.diffs = diffs;
        this.times = times;
        this.limit = limit;
        
        int i = 0;
        while(true){
            i++;
            boolean valid = solving(i);
            if(valid) break;
        }
        
        return i;
    }
    
    public boolean solving(int level){
        // 제한 시간 내 가능 여부를 리턴한다.
        long spend = 0L;
        for(int i = 0; i<diffs.length; i++){
            if(level >= diffs[i]) {
                spend += times[i];
                continue;
            }
            
            // diffs[0] = 1임이 보장되어 있고, level은 양의 정수여야 하므로
            // i == 0에서의 시행은 무조건 위 if condition을 만족한다.
            // 따라서, 아래 diffs[i-1] 연산에서 i == 0인 경우(ArrayOutOfBoundsException)에 대한 케어는 진행하지 않는다.
            // 이를 응용하여, 반복문을 i = 1부터 시작해도 좋다.
            
            spend += (times[i] + times[i-1]) * (diffs[i] - level);
            spend += times[i];
            if(limit < spend) return false; // TC 3번은 왜 여기서 못 걸러내나?
        }
        if(limit < spend) return false;   
       // System.out.printf("Whoo! %d\n", spend); // TC 3번은 위 조건문이 없으면 1724가 나온다!
        return true;
    }
}

이 코드는 level(숙련도)의 최솟값을 구하는 문제이니, 0부터 최솟값을 하나하나 증가시키며 테스트한다.

'최솟값'이니까, 0부터 시작하면 되겠지? 고 풀면 이렇게 된다. 그런데,

이렇게 풀면 틀린다. 왜?

 

?

'최솟값'이 아득하게 큰 경우가 있기 때문이다. limit을 long으로 줄 때부터 눈치를 까야 됨(하지만 나는 틀리고서야 알았지 ㅋㅋ)

나는 단순히 0부터 시작하렴 ~ 하고 걸어 놨기 때문에

최솟값부터가 엄청 큰 경우 답이 없어진다.

 

그래서 이건 이분 탐색 문제가 된다. 

 

풀이의 방향을 이분 탐색으로 정하고 나면, 바로 다음으로 생각할 거리가 생기는데

탐색 범위가 어디부터 어디까지인가? 하는 것이다.

나는 solving(int level)을 가지고 탐색 중이기 때문에

이 경우 level의 구간이 탐색 범위가 된다. 

그렇다면 level의 구간은 어디부터 어디까지인가? 

쏘 간단쓰 .. 1 ~ max(diff)가 되겠음 왜냐 

level >= diff[i]이기만 하면 time[i]에 퍼즐을 풀 수 있다 따라서

diff의 최댓값보다 level이 높은 것은 소용이 없음이다.

 

그러면 diff의 최댓값을 구해야 하는데 이거를 굳이 ... 두 개 세 개 골라 찝어가며 비교하지 말고 

O(N)으로 배열 순회하면서 int max 값 갱신하면 됨

쉬운 로직인데 왜 굳이 글로 쓰냐면 진짜 ..... 혹시나 그런 일은 없겠지만 .... 까먹지 말라고 ....................... ㅎㅎ

 

https://nogotit.tistory.com/entry/BOJ1920-%EC%88%98-%EC%B0%BE%EA%B8%B0JAVA

 

BOJ_1920 수 찾기(JAVA)

펼쳐서 문제 보기더보기문제N개의 정수 A[1], A[2], …, A[N]이 주어져 있을 때, 이 안에 X라는 정수가 존재하는지 알아내는 프로그램을 작성하시오. 입력첫째 줄에 자연수 N(1 ≤ N ≤ 100,000)이 주어

nogotit.tistory.com

이걸 참고해서, 위 코드를 이분탐색 로직으로 바꾸어 보자. 

class Solution {
    static int[] diffs, times;
    static long limit;
    
    public int solution(int[] diffs, int[] times, long limit) {
        // 할당
        this.diffs = diffs;
        this.times = times;
        this.limit = limit;
        
        // 이분탐색 포인터 정하기
        int start, end, mid;
        start = 1; // ! 
        end = 0;
        int result = Integer.MAX_VALUE;
        
        for(int i : diffs){
            if(i>end) end = i;
        } // 초기 end값 세팅(탐색할 level의 상한선)
        
        while(start <= end){
            mid = (start + end) / 2;
            if(solving(mid)) {
                // 최솟값을 찾는 것이므로 탐색 범위를 아래로 내려야 한다.
                if(result > mid) result = mid;
                end = mid - 1;
                continue;
            }
            
            start = mid + 1;
        }
        
        return result;
    }
    
    public boolean solving(int level){
        // 제한 시간 내 가능 여부를 리턴한다.
        long spend = 0L;
        for(int i = 0; i<diffs.length; i++){
            if(level >= diffs[i]) {
                spend += times[i];
                continue;
            }

            spend += (times[i] + times[i-1]) * (diffs[i] - level);
            spend += times[i];
            if(limit < spend) return false; 
        }
        
        if(limit < spend) return false;   
        return true;
    }
}

start의 초기값이 왜 1이냐면 ..... 이게 0이면 틀리는 케이스가 있다(정확히는 ArrayIndexOutOfBoundsException이 발생함(-1을 탐색, 즉 level=0일 때))

어차피 start는 level이 가질 수 있는 범위의 최소 값이고 .... level은 무조건 양의 정수라고 문제에서 명시하고 있기 때문에, 1을 지정해 주면 된다. 

 

이분탐색을 활용해야 모든 케이스를 통과할 수 있다.

'2025 > Solving' 카테고리의 다른 글

PGMRS_유연근무제(JavaScript)  (0) 2025.05.10
PGMRS_석유 시추(PCCP 기출, JAVA)  (2) 2025.04.26
BOJ_25192 인사성 밝은 곰곰이(JAVA)  (0) 2025.04.11
BOJ_1920 수 찾기(JAVA)  (0) 2025.04.11
BOJ_7569 토마토(JAVA)  (0) 2025.04.06

댓글