二分法专题-lintcode二分法问题解惑
来源:互联网 发布:linux编译环境搭建 编辑:程序博客网 时间:2024/06/05 20:47
二分法是常考的算法,适用于:在一个有序的序列中,找第一个满足某条件的位置(当然也可以找满足某条件的最后一个位置)
学习过程中让人迷惑的问题有:
- 上下限的确定,low=0,high=n-1还是low=0,high=n
- 循环条件low<high还是 low<=high
- 循环中low=mid还是low=mid+1,high=mid还是high=mid-1
- 有些情况无法退出循环,即是要mid=(low+high)/2还是mid=(low+high+1)/2 (即向左偏还是向右偏)
通过例子来帮助理解,不需要死记硬背
最普通的二分查找
int findPosition(vector<int> &nums, int target) { // write your code here //二分查找 if(nums.size()==0) return -1; int low=0,high=nums.size()-1; int mid; while(low<=high){ mid=low+(high-low)/2; if(nums[mid]==target) return mid; if(nums[mid]<target){ low=mid+1; } else{ high=mid-1; } } //循环结束,没有返回,则不存在 return -1; }
- 上下限要覆盖所有的可能,故n-1就足够了,当然扩大一些,上限为n也可以
- 这里要找等于target的数,这样写循环结束后low>high,[low,high]无法构成区间,通过此判断是否存在,故写成low<=high
第一个满足某条件的位置,最后一个满足某条件的位置
我们将最后一个满足某条件a的位置转换为求第一个!a的位置,再-1即可,可避免一些问题
即求最后一个满足a<=sqrt(x)的数,可以直接求,也可以转化为第一个满足a>sqrt(x)的位置,然后再减1
我们先分析第二种的写法
- low=0,上限是多少?high=x当然没错,但可以更小一些。sqrt(x)不可能超过x/2,即求sqrt(100)不会超过50,sqrt(101)不会超过50.5,但c++中除法会得到50,故x/2+1。但注意,我们现在是要求a>sqrt(x)的位置,故还要向后放一个,x/2+2。总结下:直接求a<=sqrt(x)的最后一个数,low=0,high=x/2+1;求a>sqrt(x)的第一个位置:low=0,high=x/2+2
- 若mid*mid<=x则low=mid+1,因为我们要找的是a>sqrt(x)的第一个位置,mid*mid<=x后是取不到mid的故low=mid+1而不是low=mid,同理,mid*mid>x时,可以取到mid,high=mid
- 是否需要右偏?不需要,因为循环条件low<high,最后low,high到了相邻位置,(low+high)/2向左偏,到了low,可以通过low=mid+1破坏循环条件,从而退出
代码如下:
int sqrt(int x) { // write your code here //将上界放为x/2+2 long low=0,high=x/2+2; long mid; //这里尝试一种更好理解的方法:找到第一个mid*mid>x的数,再-1即可 //一旦使用这种方法,上界需要改为x/2+2 while(low<high){ mid=low+(high-low)/2; if(mid*mid<=x){ low=mid+1; } else{ high=mid; } } //返回夹出的位置-1 return low-1; }
直接求a<=sqrt(x)的最后一个位置:
区别在于上限为x/2+1,mid*mid<x则low=mid(因为这里mid可能就是<sqrt(x)的最后一个数),mid*mid>x,则high=mid-1。这里只能通过high=mid-1破坏low<high的循环条件,故应该右偏mid=(low+high+1)/2,最后注意应该返回high
所以求最后一个位置还是推荐转化为第一个位置-1
int sqrt(int x){ long low=0,high=x/2+1; long mid; while(low<high){ //注意这里的二分,要向右偏 //如果不向右偏,x=50,low=7,high=8,会一直循环下去; //向右偏,low=7,high=8,然后mid=8>50故high=7,返回7即可 mid=low+(high-low+1)/2; if(mid*mid==x){ return mid; } else if(mid*mid<x){//sqrt在右侧,注意这里可能等于mid,不应写low=mid+1 low=mid; } else{//sqrt在左侧 high=mid-1; } } //注意这里不能返回low return high; }
其他类似题目
即找第一个>=target的位置,再找第一个>target的位置-1
先对第0列的数二分,找最后一个<=target的数的位置即第一个>target的位置-1,这样就可以确定target在哪行,然后对这一行用最基本的二分查找即可
类似的题目还有很多
阅读全文
1 0
- 二分法专题-lintcode二分法问题解惑
- HNUST专题练习:二分法
- 二分法~~
- 二分法
- 二分法
- 二分法
- 二分法
- 二分法
- 二分法
- 二分法
- 二分法
- 二分法
- 二分法
- 二分法
- 二分法
- 二分法
- 二分法
- 二分法
- 学习笔记04(MySQL数据库做用户登陆)
- BP算法纯理论推导
- 欢迎使用CSDN-markdown编辑器
- SSL--VPN未分配虚拟ip地址问题
- unity基础,控制游戏目标
- 二分法专题-lintcode二分法问题解惑
- [KD树] BZOJ5005. 乒乓游戏
- 成绩处理
- 二叉树的简单介绍和二叉树的二叉链表存储表示
- Pycharm中添加2to3工具
- 学习记录一
- C++中友元的用法
- uva1637(记忆化搜索)
- 括号匹配问题