35.搜索插入位置(二分查找例题)
思路:
因为题目中说明了数组是排序数组,这是使用二分查找的前提条件,所以我们考虑这道题是否可以使用二分查找的方法来解决。
这道题使用二分查找会出现两种情况,第一种情况是在数组中我们找到了相应的目标值,那么这道题就是最简单的二分查找题目,我们可以通过基础的模板来解决。第二种情况就是在数组中我们找不到对应的值,那么我们需要返回它将被按顺序插入的位置,即我们需要找到最后一个小于它的数或者第一个大于它的数,如果找最后一个小于它的数,则返回结果为最后一个小于它的数的位置+1;如果找第一个大于它的数,返回的结果就是第一个大于它的数的位置。
由题目可以知道,示例2和示例3都是第二种情况,所以我们对示例2和示例3进行二分查找模拟。
当使用左闭右闭区间时:
按照示例2所示:
left | right | middle | nums[middle] |
---|---|---|---|
0 | 3 | 1 | 3 |
0 | 0 | 0 | 1 |
1 | 0 |
按照示例3所示:
left | right | middle | nums[middle] |
---|---|---|---|
0 | 3 | 1 | 3 |
2 | 3 | 2 | 5 |
3 | 3 | 3 | 6 |
4 | 3 |
根据上述示例2和示例3,我们可以知道二分查找退出循环后,left代表的就是第一个大于目标值的数,而right代表的就是最后一个小于目标值的数。
当使用左闭右开区间时:
按照示例2所示:
left | right | middle | nums[middle] |
---|---|---|---|
0 | 4 | 2 | 5 |
0 | 2 | 1 | 3 |
0 | 1 | 0 | 1 |
1 | 1 |
按照示例3所示:
left | right | middle | nums[middle] |
---|---|---|---|
0 | 4 | 2 | 5 |
3 | 4 | 3 | 5 |
4 | 4 |
根据上述示例2和示例3,我们可以知道二分查找退出循环后,left和right都是代表第一个大于目标值的数。
我对上述结果的思考是:在正常的二分查找中,如果我们想要找到排序数组中的一个值,那么left和right都是会逐渐逼近这个值的,在正常的情况下,如果排序数组中有这个值,那么只需要left或者right搜寻到就可以了。但是如果排序数组中没有这个值,我们在搜索的过程中是一定遇到left==right的情况,当我们使用的是左闭右闭的区间时,当left>right时,循环才会结束,我们需要考虑left与right相等时的情况,如果相等时的值是大于目标值的话,那么right需要减一,然后结束循环,如果相等时的值是小于目标值的话,那么left需要加1,所以目标值是在区间[right,left]之间的,所以我们的结果应该为left+1或者right。当我们使用的是左闭右开的区间的话,当left与right相等时,循环就结束了,那我们是否可以这么认为nums[left]<target和nums[right]>target在二分查找的整个过程中是一直成立的,那么在left等于right的前一步应该总是left+1=right的情况,然后再跳到left=right的情况,所以在循环结束后,left和right都是第一个大于target的数,所以直接输出就可以了。
代码:
左闭右闭区间的两种代码:
class Solution {
public int searchInsert(int[] nums, int target) {
int left=0;
int right=nums.length-1;
while(left<=right)
{
int middle=left+(right-left)/2;
if(nums[middle]>target)
{
right=middle-1;
}
else if(nums[middle]<target)
{
left=middle+1;
}
else
return middle;
}
return right+1;
}
}
class Solution {
public int searchInsert(int[] nums, int target) {
int left=0;
int right=nums.length-1;
while(left<=right)
{
int middle=left+(right-left)/2;
if(nums[middle]>target)
{
right=middle-1;
}
else if(nums[middle]<target)
{
left=middle+1;
}
else
return middle;
}
return left;
}
}
左闭右开区间的两种代码:
class Solution {
public int searchInsert(int[] nums, int target) {
int left=0;
int right=nums.length;
while(left<right)
{
int middle=left+(right-left)/2;
if(nums[middle]>target)
{
right=middle;
}
else if(nums[middle]<target)
{
left=middle+1;
}
else
return middle;
}
return right;
}
}
class Solution {
public int searchInsert(int[] nums, int target) {
int left=0;
int right=nums.length;
while(left<right)
{
int middle=left+(right-left)/2;
if(nums[middle]>target)
{
right=middle;
}
else if(nums[middle]<target)
{
left=middle+1;
}
else
return middle;
}
return left;
}
}