二分法
在網上搜,能看見比較詳細的二分法的介紹,但是筆者還是想去梳理一下,因為想要真正了解二分法的代碼和二分法的原理是不一樣的。首先,看一個比較常用的二分法算法。
public int binarySearch(int nums[],int target){
Arrays.sort(nums);
int left=0,right=nums.length-1;
while(left<=right){
int mid=(left+right)/2;
if(nums[mid]==target){
return mid;
}
else if(nums[mid]>target){
right=mid-1;
}
else {
left=mid+1;
}
}
return left;
}
我們主要從兩個邊界問題來考慮這個函數會怎麼樣:
-
如果nums的取值範圍在[a,b],并且target值屬于[a,b],但是target不等于nums中的任意元素。對于這種情況下,我們能夠得到binarySearch傳回一個index值,但是nums[index]并不對于target。
如nums=[0,1,2,3,4,5,6,7,8] target=2.5
最終輸出的值為3,因為找不到target。輪次 left right mid 1 8 4 2 3 1 3 2 3 2 4 3 3 3 5 3 2 2 -
如果nums的取值範圍在[a,b],并且target值不屬于[a,b],則會出現超過數組的index
如nums=[0,1,2,3,4,5,6,7,8] target=9
輪次 left right mid 1 8 4 2 5 8 6 3 7 8 7 4 8 8 8 5 9 8 8 最終輸出的值是9,找不到index。
這個方法我們再找最終輸出的index是否滿足要求,需要判斷index是否在nums數組範圍的同時判斷nums[index]是否對于target,這樣子就比較麻煩,是以需要改進一下算法
public int binarySearch(int nums[],int target){
Arrays.sort(nums);
int left=0,right=nums.length-1;
while(left<right){
int mid=(left+right)/2;
if(nums[mid]==target){
return mid;
}
else if(nums[mid]>target){
right=mid;
}
else {
left=mid+1;
}
}
return left;
}
該方法就不會越界,但是還是需要判斷nums[index]是否等于target。
- 那麼對于nums=[0,1,2,3,4,4,4,5,6,7],target=4,并且我想得到最左邊的4的下标,我們怎麼改進算法呢?
public int binarySearch(int nums[],int target){ Arrays.sort(nums); int left=0,right=nums.length-1; while(left<right){ int mid=(left+right)/2; if(nums[mid]>=target){ right=mid; } else { left=mid+1; } } return left; }
-
同理,我們想找到最右邊的4的下表,我們應該怎麼改進呢?
可以思考一下,然後見下面的答案:
注意這個mid是如何取值的,本質上也是相對于去最左邊值的對偶關系public int binarySearch(int nums[],int target){ Arrays.sort(nums); int left=0,right=nums.length-1; while(left<right){ int mid=(left+right)/2+(left+right)%2; if(nums[mid]<=target){ left=mid; } else { right=mid-1; } } return right; }
-
那麼介紹完了二分法了之後,可以嘗試做一下leetcode題目
https://leetcode-cn.com/problems/minimum-time-to-complete-trips/