二分查找基础:
二分查找
题目链接 Loading Question... - 力扣(LeetCode)
最开始的题解:
class Solution { public: int search(vector<int>& nums, int target) { int left = 0 ; int right = nums.size() ; if (left < right){ while(left < right){ int middle = (left + right) / 2 ; if(nums[middle] > target){ right = middle ; } else if(nums[middle] < target){ left = middle ; } else if(nums[middle] == target){ return middle ; } } return -1 ; } else{ return -1 ; } } };
提交结果是超出时间限制。
在本地调试执行后发现是对边界理解有问题。左右边界在此时必不会有 = middle的情况,本来搜索范围在闭区间里,实际上我的循环更新边界,更新后的边界都在区间外,更新后的区间实际上是个开区间,但是循环条件确是闭区间。所以肯定会死循环。
我这种写法会导致如果target为数组中缺失数,出现middle不为整数的情况,导致进入死循环,所以超出时间限制。
修改后
class Solution { public: int search(vector<int>& nums, int target) { int left = 0 ; int right = nums.size() - 1 ; if (target > nums[right] || target < nums[left]){ return -1 ; } if (left <= right){ while(left <= right){ int middle = left + (right - left) / 2 ; if(nums[middle] > target){ right = middle - 1; } else if(nums[middle] < target){ left = middle + 1; } else if(nums[middle] == target){ return middle ; } else { return -1 ; } } return -1 ; } else{ return -1 ; } } };
考虑了题目情况,数组为顺序排列。如果target大于数组边界值或小于数组边界值,可以直接返回 -1而不用进行二分查找。
最后根据标准解题方法过了一遍。
class Solution { public: int search(vector<int>& nums, int target) { int left = 0 ; int right = nums.size() - 1 ; while(left <= right){ int middle = left + (right - left) / 2; if(target > nums[middle]){ left = middle + 1; } else if(target < nums[middle]){ right = middle - 1; } else{ return middle; } } return -1; } };
个人理解的重点在边界条件判断,不管是循环条件还是更新区间,必须符合区间定义。称之为循环不变量。
搜索插入位置
题目链接 35. 搜索插入位置 - 力扣(LeetCode)
int search(vector<int>& nums, int target) { int left = 0 ; int right = nums.size() - 1 ; if (target <= nums[left]) { return left ; } if (target > nums[right]){ return right + 1 ; } else if (target == nums[right]) { return right ; } while(left <= right){ int middle = left + (right - left) / 2 ; if(nums[middle] > target){ right = middle - 1; } else if(nums[middle] < target){ left = middle + 1; } else if(nums[middle] == target){ return middle ; } } return left ; }
主要重点在于理解边界条件的判断。我这个写法有点冗余了.
在排序数组中查找元素的第一个和最后一个位置
题目链接 34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { int leftBorder = getLeftRange(nums, target); int rightBorder = getRightRange(nums, target); if (leftBorder == -2 || rightBorder == -2) return {-1,-1}; if (rightBorder - leftBorder > 1) return {leftBorder + 1, rightBorder - 1}; return {-1, -1}; } private: int getLeftRange(vector<int>& nums, int target) { int left = 0 ; int right = nums.size() - 1 ; int leftBorder = -2 ; while(left <= right){ int middle = left + (right - left) / 2 ; if(nums[middle] >= target){ right = middle - 1; leftBorder = right; } else{ left = middle + 1; } } return leftBorder; } int getRightRange(vector<int>& nums, int target) { int left = 0 ; int right = nums.size() - 1 ; int rightBorder = -2 ; while(left <= right){ int middle = left + (right - left) / 2 ; if(nums[middle] > target){ right = middle - 1; } else{ left = middle + 1; rightBorder = left; } } return rightBorder; } };
修改出来的标准写法。不过还是没有理解为什么要这样去找左右边界。需要下来继续研究吃透这题的原理。
标签:right,target,nums,int,Day1,middle,left,LeetCode,刷题 From: https://www.cnblogs.com/tianmaster/p/16842194.html