[Binary Search, Medium] Koko Eating Bananas

송재호·2025년 4월 2일
0

https://leetcode.com/problems/koko-eating-bananas/description/?envType=study-plan-v2&envId=leetcode-75

k를 구하는 이분 탐색인 것 같다.
따라서 mid값이 바뀔 때마다 바나나를 전부 먹을 수 있는지 체크하는 로직이 있어야 함

다만 문제는 start가 몇이고 end가 몇인가.. ?
start는 당연히 1일거고, end는 piles에서 가장 큰 값으로 한 번 줘보는게 좋겠다.

그래서 풀어봤는데.. 통과는 하는데 런타임과 메모리가 마음에 안든다.
성능에 이상을 주는 부분은 없는거같은데.. 최적화를 어떻게 할 수 있을까?

(최적화 전 코드)

class Solution {
    public int minEatingSpeed(int[] piles, int h) {
        
        int start = 1;
        int end = 0;
        for (int p : piles) {
            end = Math.max(end, p);
        }

        while (start <= end) {
            int mid = start + (end - start) / 2;
            
            int result = canEat(piles, h, mid);
            if (result == 1) {
                end = mid - 1;
            } else {
                start = mid + 1;
            }
        }

        return start;
    }

    private int canEat(int[] piles, int h, int k) {
        int time = 0;
        for (int i=0; i<piles.length; i++) {
            // 이미 못하는 걸 알기 때문에 더 수행할 필요 없음
            if (time > h) {
                break;
            }

            if (piles[i] <= k) {
                time++;
            } else {
                time += Math.ceil((double) piles[i] / k);
            }
        }
        return time <= h ? 1 : -1;
    }
}

(최적화)

  1. canEat은 boolean을 리턴하는게 더 직관적일 듯. 어차피 2개 플래그밖에 없음
  2. 굳이 캐스팅까지 해가면서 Math.ceil 할 필요 없음
    2-1. 나눈 것을 더하고, 모듈러 결과가 0이 아니면 한 번 더 더해줄 수 있음
    2-2. Ceil Division 트릭을 사용할 수 있음 ((pile + k - 1) / k)
  3. 현재도 논리적 문제는 없으나.. 이진탐색 범위 start < end로 고정해 두고,
    end = midstart = mid + 1 하면 항상 결과값이 start에 남게 됨
class Solution {
    public int minEatingSpeed(int[] piles, int h) {
        int start = 1;
        int end = 0;
        for (int p : piles) {
            end = Math.max(end, p);
        }

        while (start < end) {
            int mid = start + (end - start) / 2;
            if (canEat(piles, h, mid)) {
                end = mid;
            } else {
                start = mid + 1;
            }
        }

        return start;
    }

    private boolean canEat(int[] piles, int h, int k) {
        int time = 0;
        for (int pile : piles) {
            time += (pile + k - 1) / k;
            if (time > h) return false;
        }
        return true;
    }
}
profile
식지 않는 감자

0개의 댓글