注:该文章适合已经理解二分查找基本原理的同学食用
1.算法简单原理
二分查找(折半查找)是对一个有序数组进行数据的高效查找操作,通过
每次查找中间那个数并进行折半操作实现。
相信大家在看完二分查找基本原理后觉得很简单,那么来试着练一下接下
来几道面试试题试试吧
2.搜索插入位置
这是一道典型的二分题目
原因1:数组有序
原因2:时间复杂度为O(log n)
一般只要分析情景后发现是个有序的序列就可以考虑使用二分了
方法想到了,接下来就是具体怎么写代码了
理解题目吃力没有关系,首先分析示例
示例1: :3 <= 5 <= 5,所以5应该插入到数组的第3个位置,也就是下标为2的位置,所以输出2;其中5挤掉了原来的5,占据了它的位置
分析一下,为什么是插入到第三个位置。
示例2: 1 <= 2 <= 3,所以2应该插入到数组的第2个位置,也就是下标为1的位置,所以输出1;其中2挤掉了3,占据了它的位置
不难发现,我们只要找到target大于左边而小于等于右边的数就算满足条件,想到这些就可以开始写代码了`
//下面是每次查找需要做的事情
int mid = (left+right) >> 1;//找中间值下标
if(nums[mid] >= target)//如果中间值大于等于目标值,舍弃右区间
//(因为右区间全部都大于等于目标值,而且下标更大,肯定不是我们要找的数)
{
right = mid - 1;
ans = mid;//记录满足条件的值的下标
}
else//如果中间值小于目标值,舍弃左区间
// 因为目标值肯定在右边,我们需要到右边去找,左区间已经没用了
{
left = mid + 1;
}
给你一个数组[1,2,2,2,2,2,3,4]去找2的插入位置,按照上面代码ans最后会走到哪里呢?
对,是最左边那个2,因为一旦满足要求,右区间就会全部舍弃,最后留下的就是那个满足要求的数就是我们题目中要的值了
这类题型可以总结为,找到大于等于目标值target的最小下标;
现在你可以去力扣试试这道题能不能敲出来了,注意边界
好了,现在的你已经信心满满了吧,不急,为了测试你是否已经掌握,再来练一道题试试
3.X的平方根
老规矩,看示例
这道题最先想到的应该是暴力解法,让 i 从 1 开始遍历,每次循环加 1 ,一旦发现 i 的平方大于 x ,就返回 i - 1。
可以是可以,不过效率太低,很容易发现,这道题的数也是有序的,那么我们是不是可以使用二分法呢?
暴力是从 1 遍历到 i - 1,这中间数组都是有序,我们虽然不知道 i-1 的值,但知道 i-1 作为 x 的平方根,肯定是小于 x 的所以我们是不是可以在[ 1 , x ]中使用二分来找到 i-1 呢
不难发现,我们只要找到 i 的平方小于等于 x 且 i+1 的平方大于 x就算满足条件,是不是和第一题很像呢,那么代码怎么写?
//下面是每次查找需要做的事情
int mid = (left+right) >> 1;//找中间值下标
if(mid * mid <= target)//如果中间值平方小于等于目标值,舍弃左区间
//(因为左区间全部都小于等于目标值,而且比当前值更小,肯定不是我们要找的数)
{
left = mid +1;
ans = mid;//记录满足条件的值
}
else//如果中间值平方大于于目标值,舍弃右区间
// 因为目标值肯定在左边,我们需要到左边去找,右区间已经没用了
{
left = mid + 1;
}
示例2中
相当于给你一个数组[1,2,3,4,5,6,7,8]去找 i 的平方小于等于 8 且 i+1 平方大于8,按照上面代码ans最后会走到哪里呢?
对,是那个2,因为一旦满足要求,左区间就会全部舍弃,最后留下的就是那个满足要求的数就是所有满足要求中最大的那个值了
这类题型可以总结为,找到小于等于目标值target的最大下标;
3.总结
找到小于等于目标值target的最大下标 的题型判断条件就是 <= target,
因为是要找最大,所以满足条件舍弃左(左边都更小),反之舍弃右,不难理解吧
另一个相反,可以尝试自己总结
现在你基本了解二分法的本质了,为了测验你是否真的完全掌握,打开你的力扣,拿下面这道题练练手吧
4.在排序数组中查找元素的第一个和最后一个位置
好了,掌握了这三道题,只要是二分,估计面试官也拿你没办法了,面试成功率up,祝早日找到心仪的工作吧