二分查找解题
我的第一版代码是:
class Solution { public: int search(vector<int>& nums, int target) { int left,right; left=0; right=nums.size()-1; int mid=(right+left)/2; while(nums[mid]!=target){ if(target>nums[mid]&&left!=right){ left=mid+1; mid=(right+left)/2; } else if(target<nums[mid]&&left!=right){ right=mid-1; mid=(right+left)/2; } else if(left>=right){ return -1; break; } } return mid;} };思路是,如果找到了mid等于目标,就返回mid,如果没找到,就进入while循环。如果目标大于中间值,说明中间值不会是目标,left=mid+1,但如果左右都挨着了,目标大于最右边或者小于最左边,就不再继续了,所以写了left!=right,同理如果左边大于等于右边,也就是中间值已经不再区间内了,就return -1.
我觉得特别完美。
但是只通过了6个实例。
我非常难过。
第三个分支else if (left >= right)只有在前两个条件都为假时才会执行。
随即更换成更简单的循环思路:当left小于等于right时循环,这样如果超出了就直接返回-1,
class Solution { public: int search(vector<int>& nums, int target) { int left,right; left=0; right=nums.size()-1;//// 定义target在左闭右闭的区间里,[left, right],还有一种做法是左闭右开 int mid=(right+left)/2; while(left<=right){ if(target>nums[mid]){ left=mid+1; mid=(right+left)/2; } else if(target<nums[mid]){ right=mid-1; mid=(right+left)/2; } else return mid; } return -1; } };开篇之作!
做第二道题,准备用左闭右开的方法:
class Solution { public: int searchInsert(vector<int>& nums, int target) { int left=0; int right=nums.size();//左闭右开 while(left<right){ int mid=(left+(right-1))/2; if(target>nums[mid]){ left=mid+1;//这里第一次做错了,左闭,记得加一 } else if(target<nums[mid]){ right=mid; } else return mid; } return left; } };为什么左闭就要加1,右闭就要减1呢,不加不减就会超时?
解释“左闭”意味着left索引在搜索范围内。当nums[mid] < target时,mid位置已被检查且不符合要求,所以必须从区间中剔除。因为左端是“闭”的(包含),如果设置left = mid,就会把不合格的元素重新圈进来,导致区间无法缩小(死循环)。所以必须left = mid + 1。
