开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情
二分查找
什么是二分查找呢?
二分查找又叫折半查找,每次查找之后都能去掉一半的数据。二分查找的前提是查找的数据必须有序的。二分查找的时间效率非常高,对于数据量为n的有序序列,时间复杂度为O(log(n))
力扣35题:搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
示例 1: 输入: nums = [1,3,5,6], target = 5 输出: 2
示例 2: 输入: nums = [1,3,5,6], target = 2 输出: 1
示例 3: 输入: nums = [1,3,5,6], target = 7 输出: 4
思路:首先题目明确要求时间复杂度为O(long(n)),然后发现数组是有序,显然就是要用二分查找。
怎么二分查找?
二分查找要在区间[left,right](区间左右边界可以相等)中确定中间值的下标mid,通过这个mid对应的中间值和目标值target进行比较。
有三种比较结果
1.中间值小于目标值——nums[mid]<target
说明target在mid右边,下次查找是的区间就变成[mid+1,right]
2.中间值大于目标值——nums[mid]>target
说明target在mid左边,下次查找是的区间就变成[left,mid-1]
3.中间值大于目标值——nums[mid]==target
说明找到了,直接返回下标mid
当我们把整个数组查找完的时候,都没有查找到target,就说明要返回target插入的位置.target插入的位置无非就这3种情况.
可以把这个3种情况一起解决吗?
当查找不到的时候,说明区间已经不存在了,即left大于right,那么left就是target应该插入的地方.
为什么呢?
查找不到前的最后一个区间必是left==right,前面我说的是区间的左右边界是可以相等的.
那么模拟最后一步:mid还是为left,假如target大于nums[mid],那么应该插入mid的右边1位,而此时left就是mid+1;小于的情况,就不用我明说了吧;没有等于的情况哈,因为前提就是不存在.
完整代码
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left=0;//左边界
int right=nums.size()-1;//右边界
while(left<=right)//区间要存在
{
int mid=(left+right)/2;//中间位置
//3种比较结果
if(nums[mid]<target)
left=mid+1;
else if(nums[mid]>target)
right=mid-1;
else
return mid;
}
//没有查找到,返回插入的位置
return left;
}
};