搜索插入位置Leetcodehttps://leetcode.cn/problems/search-insert-position/
题目粘贴:
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 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(log n),所以我使用二分查找来完成。找到目标值较为简单,本题中,由于目标值未必存在,所以如果目标值不存在,我们就要返回适合它插入的位置(数组是有序的)。我们重点来看一下如何找到正确的插入位置
代码:
class Solution {
public int searchInsert(int[] nums, int target) {
int l=0,r=nums.length-1;
while(l<=r)
{
int mid=(l+r)/2;
if(nums[mid]==target)
{
return mid;//如果找到目标值,就返回
}else if(nums[mid]<target)//如果目标值在mid的右边
{
l=mid+1;
}else//如果目标值在mid左边
{
r=mid-1;
}
}
return l;//如果没有找到目标值,就返回L,当作要插入的位置
}
}
解题思路:
先看上面的代码,很多朋友可能不理解,为什么L始终为要插入的地方。
先看我们的循环条件:while(l<=r)。也就是说:如果没找到目标值,L指向的位置一定是大于R的,对不对?
要想L>R,又分为两种情况:
1.R移到了L的左边,在二分查找中,当目标值小于mid的时候,R才需要左移。
2.L移到了R的右边,同上,目标值大于mid的时候,L才需要移动,并且是右移。
也就是说:当没有找到目标值的时候,循环结束,L一定是在R的右边,L=R+1;
接下来我将给出推理过程,不管是情况1结束循环还是情况2结束循环,目标值的插入位置都为L;
情况1:R移到了L的左边
假设此时以下面这个存储五个元素的数组arr为例,我们将所要寻找的目标值target设为6。
L,mid,R分别为:left,middle,right的缩写,区间为左闭右闭;
L和R的初始值分别指向0和arr.length-1,此时寻找的范围为[0,4];
计算mid的值为:mid=(L+R)/2=(0+4)/2=2;
因为arr[mid]=arr[2]=5<6的值,所以mid以及mid左边的值可以不考虑了
缩小要查找的范围,往mid右边找,L=mid+1=3;如下图:
此时要查找到范围为[3,4],mid=(L+R)/2=(3+4)/2=3;mid和L指向同一位置。
重点:
因为,arr[3]=7>6,此时arr[3]上的值大于target,所以接下来应该往左找
R=mid-1=3-1=2;此时范围如下图:R移至L的左边,不满足循环条件,循环结束。
此时L指向的位置就是目标值应该插入的位置。
情况2:L移到了R的右边
还是这个数组,只不过这次我们将目标值target的值改为:4
计算mid的值为:mid=(L+R)/2=(0+4)/2=2;
arr[2]=5>4,所以接下来应该往左找,缩小范围,将R指向mid减一。
mid=(L+R)/2=(0+1)/2=0;此时mid和L指向同一位置。
arr[mid]=1<4,所以往右找,移动L的位置,L=mid+1=1
此时L和R指向同一个位置,但是我们的循环条件是L<=R,此时仍然满足循环条件,并且也没有找到目标值。所以循环继续,mid=(L+R)/2=1;如上图,此时L,M,R指向同一处。arr[m]=3<4
所以L还要往右边移动,L=mid+1=2;如下图:
此时L指向索引为2,R指向索引1。所以L>R不满足循环条件,跳出循环,此时目标值应插入的位置依然为L所指;所以,如果没找到目标值,循环结束后,不管什么样的情况,L一定在R右边并且等于R+1;