
題目解析:有 n 堆香蕉,規定要在 h 小時內全部吃完。每個小時只能選一堆吃 k 根,如果該堆數量不夠 k 根就會全部吃完並休息到這小時結束。目標是找出能在規定時限內吃完的最小吃香蕉速度
解題思路:為了快速鎖定答案直接套用二分搜尋法。設速度的最小值 i 為 1,最大值 j 為陣列裡數量最多的一堆。丟進迴圈開始跑,每次取中間值當作目前測試的速度。接著跑內部迴圈,精算以這個速度吃完每堆香蕉需要幾小時(利用 (p - 1) / mid + 1 的技巧達成無條件進位效果)並全部加總。如果總花費時間小於或等於規定的 h 小時,代表速度過關甚至能再放慢,就把範圍縮到左半邊;如果超時,代表吃太慢了,把速度下限拉高往右半邊找。最後迴圈結束回傳 i 即可
class Solution {
public:
int minEatingSpeed(vector& piles, int h) {
int i = 1, j = *max_element(piles.begin(), piles.end());
while(i < j){
int mid = i + (j - i) / 2;
long long hours = 0;
for(int p : piles){
hours += (p - 1) / mid + 1;
}
if(hours <= h){
j = mid;
}else{
i = mid + 1;
}
}
return i;
}
};

題目解析: 在一個陣列中找出任意一個「峰值」並回傳它的索引。峰值的定義是該數字必須嚴格大於左右兩邊相鄰的數字,且題目特別要求演算法的時間複雜度必須限制在 O(\log N)
解題思路:只要看到時間複雜度被限制在 $O(\log N)$,毫無懸念就是使用二分搜尋法。設定左右指標 i 跟 j 包住整個陣列的頭尾,然後丟進迴圈跑。每次挑出中間位子,拿它跟右邊相鄰的數字做比較。如果中間數字比右邊小,代表地形正在「走上坡」,右半邊絕對藏著峰值,就把搜尋範圍往右邊縮;反之如果中間比較大,代表左半邊才有峰值,就把範圍往左邊逼近。不斷重複這個動作直到左右指標相遇夾擊,該位子就是我们要找的峰值,最後回傳 i
class Solution {
public:
int findPeakElement(vector& nums) {
int i = 0, j = nums.size() - 1;
while(i < j){
int mid = i + (j - i) / 2;
if(nums[mid] < nums[mid + 1]){
i = mid + 1;
}else{
j = mid;
}
}
return i;
}
};