二分查找
一.前言
二分法:理解十分的容易,但就是一学就会,一写就废,总会把区间问题搞错,进而导致最后的结果不对。我会以一种记录自己学习方式的形式来总结一下二分法的区间问题,有不对的可以相互探讨加以改正😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄
[low,high]左闭右闭
[low,high)左闭右开
二分法求的目标值 默认在有序递增的素组中
- 取值问题
在c/c++中的取值都是向下取整,所以数组的奇数和偶数都可以取到mid值
例题
二.分查找的两种范围
1.左闭右闭
- [low,high]
分析:
- 因为左闭右闭,所以int low=0;
int high=nums.size()-1;
int low=0;
int high=nums.size()-1;
- [low,high] 左闭右闭区间范围,及low和high的关系可以存在一个合法的公式low<=high
例如:[1.1]在low<=high是一个合法的范围
while(low<=high)
- 如果mid小于target那么low要更新初始值
- 但mid已经小于target了,所以当low=mid不符合条件,
因此low=mid+1
(左闭右闭 的思想中明确指出low是一个可取到的值)
if(nums[mid]<target)
{
low=mid+1;
}
- 同理:
如果mid大于target那么high要更新初始值
但mid已经大于target了,所以当high=mid不符合条件,
因此high=mid-1
(左闭右闭 的思想中明确指出high是一个可取到的值)
if(nums[mid]>target)
{
high=mid-1;
}
- 最后一个mid=target,直接返回mid
if(nums[mid]==target){
return mid;
}
代码力扣编号704题[左闭右闭]:
class Solution {
public:
int search(vector<int>& nums, int target)
{
int low=0;
int high=nums.size()-1;
while(low<=high)
{
int mid=(low+high)/2;
if(nums[mid]==target){
return mid;
}
else if(nums[mid]>target)
{
high=mid-1;
}
else if(nums[mid]<target)
{
low=mid+1;
}
}
return -1;//未找到数值,这个要放到while循环的外面,避免报错
}
};
dev完整代码c++
#include<bits/stdc++.h>
using namespace std;
int search(vector<int>& nums, int target)
{
int low=0;
int high=nums.size()-1;
while(low<=high)
{
int mid=(low+high)/2;
if(nums[mid]==target){
return mid;
}
else if(nums[mid]>target)
{
high=mid-1;
}
else if(nums[mid]<target)
{
low=mid+1;
}
}
return -1;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
vector<int>a(n);
for(int i=0; i<n; i++)
{
cin>>a[i];
}
int target;
cin>>target;
int m= search(a,target);
cout<<m<<endl;
return 0;
}
2.左闭右开
- [low,high)
分析:
- 因为左闭右开,所以int low=0;
int high=nums.size();
high不包含最后一个数据
int low=0;
int high=nums.size();
- [low,high) 取不到high的数值,所以low<=high中的low=high没有意义
例如:[1.2) 右侧的2取不到,只能取到小于2的数
while(low<high)
- 如果mid小于target那么low要更新初始值
- 但mid已经小于target了,所以当low=mid不符合条件,
因此low=mid+1
(左闭右开 的思想中明确指出low是一个可取到的值)
if(nums[mid]<target)
{
low=mid+1;
}
- 如果mid大于target那么high要更新初始值
所以high=mid
(左闭右开 的思想中明确指出high是一个不可取 的值)
if(nums[mid]>target)
{
high=mid;//右开,high取不到
}
- 最后一个mid=target,直接返回mid
if(nums[mid]==target){
return mid;
}
代码力扣编号704题[左闭右开]
class Solution {
public:
int search(vector<int>& nums, int target)
{
int low=0;
int high=nums.size();
while(low<high)
{
int mid=(low+high)/2;
if(nums[mid]==target){
return mid;
}
else if(nums[mid]>target)
{
high=mid;
}
else if(nums[mid]<target)
{
low=mid+1;
}
}
return -1;
}
};
- dev完整代码c++代码
#include<bits/stdc++.h>
using namespace std;
int search(vector<int>& nums, int target)
{
int low=0;
int high=nums.size();
while(low<high)
{
int mid=(low+high)/2;
if(nums[mid]==target){
return mid;
}
else if(nums[mid]>target)
{
high=mid;
}
else if(nums[mid]<target)
{
low=mid+1;
}
}
return -1;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
vector<int>a(n);
for(int i=0; i<n; i++)
{
cin>>a[i];
}
int target;
cin>>target;
int m= search(a,target);
cout<<m<<endl;
return 0;
}
三.总结
- 二分法的两种形按照区间的范围操作
- 循环条件与区间赋值的关系:
循环条件控制区间的赋值边界,区间赋值决定循环能不能继续
算法学习来自b站:“代码随想录”
例题来自704-二分查找-力扣
★,°:.☆( ̄▽ ̄)/$:.°★ 。结束🌼🌼🌼🌼🌼🌼