[2019 카카오 겨울 인턴십] Q04. 징검다리 건너기 (JAVA)

Jiwoo Kim·2021년 1월 7일
0
post-thumbnail

문제

설명

본 문제는 정확성과 효율성 테스트 각각 점수가 있는 문제입니다.

카카오 초등학교의 니니즈 친구들이 라이언 선생님과 함께 가을 소풍을 가는 중에 징검다리가 있는 개울을 만나서 건너편으로 건너려고 합니다. 라이언 선생님은 니니즈 친구들이 무사히 징검다리를 건널 수 있도록 다음과 같이 규칙을 만들었습니다.

  • 징검다리는 일렬로 놓여 있고 각 징검다리의 디딤돌에는 모두 숫자가 적혀 있으며 디딤돌의 숫자는 한 번 밟을 때마다 1씩 줄어듭니다.
  • 디딤돌의 숫자가 0이 되면 더 이상 밟을 수 없으며 이때는 그 다음 디딤돌로 한번에 여러 칸을 건너 뛸 수 있습니다.
  • 단, 다음으로 밟을 수 있는 디딤돌이 여러 개인 경우 무조건 가장 가까운 디딤돌로만 건너뛸 수 있습니다.

니니즈 친구들은 개울의 왼쪽에 있으며, 개울의 오른쪽 건너편에 도착해야 징검다리를 건넌 것으로 인정합니다.
니니즈 친구들은 한 번에 한 명씩 징검다리를 건너야 하며, 한 친구가 징검다리를 모두 건넌 후에 그 다음 친구가 건너기 시작합니다.

디딤돌에 적힌 숫자가 순서대로 담긴 배열 stones와 한 번에 건너뛸 수 있는 디딤돌의 최대 칸수 k가 매개변수로 주어질 때, 최대 몇 명까지 징검다리를 건널 수 있는지 return 하도록 solution 함수를 완성해주세요.

제한사항

  • 징검다리를 건너야 하는 니니즈 친구들의 수는 무제한 이라고 간주합니다.
  • stones 배열의 크기는 1 이상 200,000 이하입니다.
  • stones 배열 각 원소들의 값은 1 이상 200,000,000 이하인 자연수입니다.
  • k는 1 이상 stones의 길이 이하인 자연수입니다.

입출력 예

stoneskresult
[2, 4, 5, 3, 2, 1, 4, 2, 5, 1]33

풀이

  1. 건넌 니니즈 수 count를 기준으로 이분 탐색을 진행한다.
  2. 초기 left는 0, right는 돌다리 하나가 가질 수 있는 최댓값인 2억이다.
  3. count만큼 니니즈가 건넜을 때가 유효한지 available()에서 검사한다.
  4. 음수가 연속해서 k번 이상 나온 경우 false, 그 외의 경우 true를 리턴하고 답을 갱신한다.

검색 없이 내 힘으로 풀어낸 첫 번째 level 2 문제다!! 정말 기쁘다!!

위의 이분 탐색 로직은 곧잘 적었는데 available()에서 기준을 음수로 안 잡고 0 이하로 두는 바람에 잠깐 삽질을 했다. 해당 count의 니니즈까지 건넌 후에 0이 된 것이므로 0일 때 jumpCount를 증가시키면 안 되는데 조건을 잘못 걸어 놨던 것이다.

또, available()에서 일일히 jumpCount를 체크하지 않는 더 효율적인 방법은 없을까 생각을 해보았는데 떠오르지 않아서 일단은 이렇게 작성하였고, 다른 더 좋은 방법이 있나 프로그래머스 다른 사람의 풀이를 쓱 봤는데 보이지 않았다. 나중에 실력이 늘어서 좋은 풀이가 생각이 나면 고쳐야겠다.


코드

import java.util.*;

class Solution {
        
    private static final int MIN_COUNT = 0;
    private static final int MAX_COUNT = 200000000;

    public int solution(int[] stones, int k) {
        int left = MIN_COUNT;
        int right = MAX_COUNT;
        int answer = 0;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (available(mid, stones, k)) {
                answer = mid;
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return answer;
    }

    private boolean available(int count, int[] stones, int k) {
        int jumpCount = 0;
        for (int i = 0; i < stones.length && jumpCount < k; i++)
            if (stones[i] - count < 0) jumpCount++;
            else jumpCount = 0;
        return jumpCount < k;
    }
}

0개의 댓글