二分查找算法最主要是确定递归的选择。有相应的模板可以套用:
1)求中位值
mid = (left + right) / 2
2)确定递归思路
什么情况下递归[left, mid - 1],什么情况下递归[mid+1, right]
一般题目都比较好分析。
用leetcode的33题举例:
int search(vector<int> &nums, int target){
int l = 0, r = nums.size() - 1, m = -1;
while(l <= r){
m = (l+r) >> 1;
if(nums[m] == target)
return m;
if(nums[m] >= nums[l]){
if(nums[m] > target && target >= nums[l])
r = m - 1;
else
l = m + 1;
} else {
if(nums[m] < target && target <= nums[r])
l = m + 1;
else
r = m - 1;
}
}
return -1;
}
这里,最主要是要确定好l和r什么时候改变值,特别要注意的是nums[m] >= nums[l]这一条,不可以是nums[m]>nums[l],因为,当nums[m] == nums[l]的时候,nums[m]还是处在第一个有序数段中。边界条件要相当小心。
在leetcode答案中,看到一个先找断点的答案,思路清奇。找断点的算法可以反复琢磨一下。
int search(vector<int>& nums, int target) {
int n = nums.size();
int l = 0, r = n-1;
while(l < r && nums[l] >= nums[r]){
int m = l + (r-l)/2;
if(nums[m] > nums[r]){
l = m + 1;
}else{
r = m;
}
}
// nums[l]现在是最小值
int rot = l;
l = 0, r = n-1;
while(l <= r){
int mm = l + (r-l)/2;
int m = (mm + rot) % n;
if(nums[m] > target) r = mm-1;
else if(nums[m]< target) l= mm+1;
else return m ;
}
return -1;
}