二分是经常使用的方法,等抽时间总结一下二分的遇到的题目。注意,二分并不一定要求序列要有序,只要序列满足某种特定的特征即可。
二分的模板有两种:
一种是:找大于等于给定数的第一个位置(满足条件的第一个数)
一种是:找小于等于给定数的最后一个数(满足条件的最后一个数字)
https://www.acwing.com/blog/content/346/
二分的基本流程如下:
- 确定二分的边界
- 设计一个check函数,能够进行二分的判定方法
- 判断一下区间该如何更新 如果更新的方式是l=mid,r =
mid-1,那么在计算mid 的时候需要加1
在以下的题目中 [l,r] 指的是闭区间,这下就知道初始 l 和 r 如何取值了。
bool check(int mid){ …… return ……;}
//模板一 找满足某个条件的第一个数 即右半段
int binary1(int l, int r)
{
while(l<r)
{
int mid=(r+l)>>1;
if(check(mid) r=mid;
else l=mid+1;
}
return l;
}
//模板二 找满足某个条件的最后一个数 即左半段
int binary1(int l, int r)
{
while(l<r)
{
int mid=(r+l+1)>>1;
if(check(mid) l=mid;
else r=mid-1;
}
return l;
}
例题一
题目描述
实现函数 int sqrt(int x),计算并返回x的平方根(向下取整)
此时的 r = x/2,不需要设置为 x。还需要注意的是在求解mid的时候,如果输入的数据很大的时候,l 和 r 相加会出现溢出,因此需要将 (l+r)的范围扩大到 long long 类型,然后再进行除以2操作,最后将mid 转化为 int 类型。
class Solution {
public:
/**
*
* @param x int整型
* @return int整型
*/
int sqrt(int x) {
// write code here
int l=1,r=x/2;
if(x<2) return x;
while(l<r)
{
int mid=(l+r+1ll)>>1;
if(mid<=x/mid) l=mid;
else r=mid-1;
}
return l;
}
};
注意:上述模板只是针对二维数组中寻找存在的数字提出的模板,例题中需要针对相应的要求进行修改,比如例题一:如果给定的数字不在序列中的话需要用 找到的数组位置处的数字与目标值做比较,如果相等则返回该位置坐标,如果不相等按照题目要求返回应该要求的数字。
例题二
题目描述
请实现无重复数字的升序数组的二分查找
给定一个 元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型vector
* @param target int整型
* @return int整型
*/
int search(vector<int>& nums, int target) {
// write code here
if(!nums.size()) return -1;
int l=0,r=nums.size()-1;
while(l<r)
{
int mid=(l+r)>>1;
if(nums[mid]>=target) r=mid;
else l=mid+1;
}
if(nums[l]==target) return l;
else return -1;
}
};
class Solution {
public:
int search(vector<int>& nums, int target) {
int l=0,r=nums.size()-1;
while(l<r)
{
int mid=(l+r+1)>>1;
if(nums[mid]<=target) l=mid;
else r=mid-1;
}
return nums[l]==target?l:-1;
}
};
例题3:数的三次方根(浮点二分)
#include<iostream>
using namespace std;
double n;
bool check(double mid)
{
if(mid*mid*mid>=n) return true;
else return false;
}
int main()
{
cin>>n;
double l=-10000,r=10000;
for(int i=0;i<100;i++)
{
double mid=(l+r)/2.0;
if(check(mid)) r=mid;
else l=mid;
}
printf("%.6f",l);
return 0;
}