创作不易,感谢三连!!
一、二分查找算法思路总结
大家先看总结,然后再根据后面的题型去慢慢领悟
二、二分查找(easy)
. - 力扣(LeetCode)二分查找
思路:(模版1)正常的二分查找策略
class Solution {
public:int search(vector<int>& nums, int target){int left=0,right=nums.size()-1;while(left<=right){int mid=left+(right-left)/2;if(nums[mid]<target) left=mid+1;else if(nums[mid]>target) right=mid-1;else return mid;}return -1;}
};
三、在排序数组中查找元素的第一个位置和最后一个位置
. - 力扣(LeetCode)在排序数组中查找元素的第一个位置和最后一个位置
要注意示例3提到的边界情况!!
思路:找第一个,用左区间端点查找(模版2),找最后一个,用右端点区间查找(模版3)
class Solution {
public:vector<int> searchRange(vector<int>& nums, int target){if(nums.size()==0) return {-1,-1};//处理边界情况,否则会越界int begin=0;//区间左端点int left=0,right=nums.size()-1;while(left<right){int mid=left+(right-left)/2;if(nums[mid]<target) left=mid+1;else right=mid;//最后会落在区间的左端点}if(nums[left]!=target) return{-1,-1};//找不到else begin=left;//区间右端点right=nums.size()-1;while(left<right){int mid=left+(right-left+1)/2;if(nums[mid]<=target) left=mid;//最后会落在区间的右端点else right=mid-1;}return {begin,right};//此时至少有一个左端点,所以不可能找不到。}
};
四、x的平方根
. - 力扣(LeetCode)x的平方根
思路:右端区间二分查找法
class Solution {
public:int mySqrt(int x) {if(x<1) return 0;//处理边界情况int left=1,right=x/2;while(left<right){long long mid=left+(right-left+1)/2;if(mid*mid>x) right=mid-1;else left=mid;}return left;}
};
五、搜索插入位置
. - 力扣(LeetCode)搜索插入位置
思路1:左端区间查找
class Solution {
public:int searchInsert(vector<int>& nums, int target) {int left=0,right=nums.size()-1;while(left<right){int mid=left+(right-left)/2;if(nums[mid]<target) left=mid+1;else right=mid;}if(nums[left]<target) return left+1;return left;}
};
思路2:右端区间查找(有特殊情况,比如正好是和targe相等且只有一个元素)
class Solution {
public:int searchInsert(vector<int>& nums, int target) {int left=0,right=nums.size()-1;while(left<right){int mid=left+(right-left+1)/2;if(nums[mid]<target) left=mid;else right=mid-1;}//右端区间要考虑边界情况(特殊情况,只有一个元素且正好等于target)if(nums[left]>=target) return left;return left+1;}
};
六、山峰数组峰顶的索引
. - 力扣(LeetCode)山峰数组峰顶的索引
本题特别的就是不再是升序,而是去找二段性的规律
思路1:左端区间查找
class Solution {
public:int peakIndexInMountainArray(vector<int>& arr){int left=1,right=arr.size()-2;while(left<right){int mid=left+(right-left)/2;if(arr[mid]<arr[mid+1]) left=mid+1;else right=mid; }return left;}
};
思路2:右端区间查找
class Solution {
public:int peakIndexInMountainArray(vector<int>& arr){int left=1,right=arr.size()-2;while(left<right){int mid=left+(right-left+1)/2;if(arr[mid]>=arr[mid-1]) left=mid;else right=mid-1; }return left;}
};
七、寻找峰值
. - 力扣(LeetCode)寻找峰值
左区间端点法:
class Solution {
public:int findPeakElement(vector<int>& nums) {int left=0,right=nums.size()-1;while(left<right){int mid=left+(right-left)/2;if(nums[mid]<nums[mid+1]) left=mid+1;else right=mid;}return right;}
};
右区间端点法:
class Solution {
public:int findPeakElement(vector<int>& nums) {int left=0,right=nums.size()-1;while(left<right){int mid=left+(right-left+1)/2;if(nums[mid]>=nums[mid-1]) left=mid;else right=mid-1;}return right;}
};
八、点名
. - 力扣(LeetCode)点名
左区间端点法
class Solution {
public:int takeAttendance(vector<int>& records) {int left=0,right=records.size()-1;while(left<right){int mid=left+(right-left)/2;if(records[mid]==mid) left=mid+1;else right=mid;}if(records[right]==right) return right+1;else return right;}
};
注意:插入元素的时候要注意是否是在最右边插入!
九、 寻找旋转数组中的最小值
. - 力扣(LeetCode)寻找旋转数组中的最小值
思路:左区间端点查找法
class Solution {
public:int findMin(vector<int>& nums) {int left=0,right=nums.size()-1;int target=nums[right];//标记一下while(left<right){int mid=left+(right-left)/2;if(nums[mid]>target) left=mid+1;else right=mid;}return nums[left];}
};
十、二分查找规律的再总结
二分查找的策略基本上都是去找一个数,对应的有三种模版:正常的二分查找、左区间端点查找、右区间端点查找。其中正常的二分查找局限性比较大,必须得是升序且限制条件较多,大多数情况下不符合题意。最常用的就是左区间端点(关键是left会大跳跃,且目标位置在较大值区间的左边)和右区间端点法(关键是right会大跳跃,且目标位置在较小值区间的右边)。
后面有遇到相关oj题博主会继续更新的……感谢支持!!