二分查找的前提:数组,排列好顺序,无重复元素。
二分查找关键:left,right的初始化
while循环的循环条件
while循环中left,right的赋值;
二分查找围绕while循环的循环条件进行展开:
1:left<=rigth
2:left<rigth
当while(left<=right)时
我们默认middle=(left+right)/2;
1.考虑极端条件下的初始化:left,right是否能进入循环?
当nums.size()=1,left=0,right=nums.size()-1时:
判定left==right==0能够进入循环,满足初始化条件
2.考虑极端条件下能否退出循环,即当left==right且没有找到目标值时,如何退出循环?
此时middle=0,left=0,right=0;
理所当然需要left=middle+1,right=middle-1才能退出循环
则代码如下:
class Solution { public: int search(vector<int>& nums, int target) { int left=0,right=nums.size()-1; while(left<=right){ int middle=left+((right-left)>>1); if(nums[middle]>target) right=middle-1; else if(nums[middle]<target) left=middle+1; else return middle; } return -1; } };
当while(left<right)时
我们默认middle=(left+right)/2;
1.考虑极端条件下的初始化:left,right是否能进入循环?
当nums.size()=1,left=0,right=nums.size()-1时:
此时right=0,判定left==right,不能进入循环,说明初始化错误!
我们进行如下修改right=nums.size();
此时right=1,判定left<right,可以进入循环,初始化成功!
2.考虑极端条件下能否退出循环?
当left=n,right=n+1,此时middle=n:
假设没有找到目标值,理所当然需要left=middle+1,right=middle;
class Solution { public: int search(vector<int>& nums, int target) { int left=0,right=nums.size(); while(left<right){ int middle=left+(right-left)/2; if(target<nums[middle]) right=middle; else if(nums[middle]<target) left=middle+1; else return middle; } return -1; } };
这就是我们的左闭右开式二分查找!
放出左开右闭式二分查找代码:
class Solution { public: int search(vector<int>& nums, int target) { int left=-1,right=nums.size()-1; while(left<right){ int middle=left+(right-left)/2+1; if(target<nums[middle]) right=middle-1; else if(nums[middle]<target) left=middle; else return middle; } return -1; } };
备注:
>>1是移位运算;
left+(right-left)/2是防止溢出;