二分搜尋演算法-吃香蕉問題

life_start發表於2024-08-21

題目:

輸入一個長度為N的正整數陣列piles代表N堆香蕉,piles[i]代表第i堆香蕉的數量,現在要在H小時內吃完之這些香蕉,請求假設吃香蕉的速度為k,而且每小時最多吃一堆香蕉,如果吃不下的話留下到下一個小時再吃,如果吃完後這堆後,如果還有胃口,也要等待下一個小時才能吃下一堆。

求最小的k

分析:

1)一堆香蕉N,每小時吃K個,則一堆需要多久呢?

如果N%k=0,則需要N/k 小時

如果N%k!=0.則需要N/k + 1小時

2) 此問題最直接的解法是,k從1遍歷到max(piles[i]),因為再大已經沒有意義,最多一小時只能吃一堆,針對每個值計算是否可以在H小時吃完,計算第一個滿足的k,則是最小的k

/**
 * 有n堆食物,在H小時內吃完,每小時吃多少個食物,最小的值是多少
 */
public class MinEatingSpeed {


    public static void main(String[] args) {

        int[] piles = new int[5];
        int H = 5;
        piles[0] = 10;
        piles[1] = 20;
        piles[2] = 30;
        piles[3] = 40;
        piles[4] = 50;
        System.out.println(minEatingSpeed(piles,H));
 
    }


    public static int minEatingSpeed(int[] piles, int H) {
        int max = max(piles);
        for (int speed = 1; speed < max; speed++) {
            if(canFinish(piles,speed,H)){
                return speed;
            }
        }
        return max;
    }

    public static Boolean canFinish(int[] piles,int speed,int H){
        int count = 0;
        for (int pile : piles) {
            count = count + ((pile%speed)==0?pile/speed:(pile/speed) + 1);
//            System.out.println("pile=" + pile + " speed=" + speed + " (pile%speed)==0?pile/speed:(pile/speed) + 1=" + (count + (pile%speed)==0?pile/speed:(pile/speed) + 1));
//            count = count + (pile/speed) + ((pile%speed)>0?1:0);
        }
        return count<=H;
    }


    public static int max(int[] piles){
        int max=0;
        for (int pile : piles) {
            if(pile>max){
                max=pile;
            }
        }
        return max;
    }
}

  3)k從1開始找到max速度不夠快,可以採用二分查詢的方法,比如如果max=100,使用50,發現能在H小時內吃完,則k最小值,應該在1~50內,否則在50~100內,再次縮小到25,12,6 比直接從1遍歷要快很多

/**
 * 有n堆食物,在H小時內吃完,每小時吃多少個食物,最小的值是多少
 */
public class MinEatingSpeed {


    public static void main(String[] args) {

        int[] piles = new int[5];
        int H = 5;
        piles[0] = 10;
        piles[1] = 20;
        piles[2] = 30;
        piles[3] = 40;
        piles[4] = 50;
  
        //二分查詢
        System.out.println(minEatingSpeed2(piles,H));

    }

    public static int minEatingSpeed2(int[] piles, int H) {

        int left = 1;
        int right = max(piles) + 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if(canFinish(piles,mid,H)){
                right = mid;
            }else{
                left = mid + 1;
            }
        }
        return left;
    }



    public static Boolean canFinish(int[] piles,int speed,int H){
        int count = 0;
        for (int pile : piles) {
            count = count + ((pile%speed)==0?pile/speed:(pile/speed) + 1);
//            System.out.println("pile=" + pile + " speed=" + speed + " (pile%speed)==0?pile/speed:(pile/speed) + 1=" + (count + (pile%speed)==0?pile/speed:(pile/speed) + 1));
//            count = count + (pile/speed) + ((pile%speed)>0?1:0);
        }
        return count<=H;
    }


    public static int max(int[] piles){
        int max=0;
        for (int pile : piles) {
            if(pile>max){
                max=pile;
            }
        }
        return max;
    }
}

  

相關文章