「这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战」。
描述
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 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
示例 4:
输入: nums = [1,3,5,6], target = 0
输出: 0
示例 5:
输入: nums = [1], target = 0
输出: 0
做题
思路
因为这道题目要求了时间复杂度为O(log n),所以我们必须得了解二分法查找。
二分法查找就是给数组划定一个左右边界,再通过比较边界中间的数和目标数,然后决定边界该往哪里收缩,直到两个边界相交,就找到目标数在那个坐标上。
二分法查找大概如下。
private int binarySearch(int[] array,int target){
int l = 0,r = array.length - 1;
while (l<=r){
int middle = (l+r)/2;
if(target == array[middle]){
return middle;
}
if (target > array[middle]){
l = middle + 1;
}else {
r = middle - 1;
}
}
return -1;
}
而这道题我们不需要找到这个数,又需要找到这个数。
因为我们不是直接查找这个数,所以不需要找到这个数后就返回 middle 了。
我们还需要知道目标数可以放在哪里。
如果目标数大于数组中的所有数,那就只能放在最后,下标为数组长度减一。
如果目标数小于数组中的所有数,那就只能放在第一位,下标为 0。
剩下的就是要放在数组中间的情况,我们使用二分法会找到一个跟目标数很接近的数的下标,目标数呢是要把数组中一个下标的数以及后面的数往后挤。
下面是我修改了上面的二分法查找的代码,把返回结果改成了 middle,以下是打印结果。
System.out.println(solution5.binarySearch(new int[]{1, 3, 5, 7}, 0)); //0
System.out.println(solution5.binarySearch(new int[]{1, 3, 5, 7}, 3)); //1
System.out.println(solution5.binarySearch(new int[]{1, 3, 5, 7}, 4)); //2
System.out.println(solution5.binarySearch(new int[]{1, 3, 5, 7}, 5)); //2
System.out.println(solution5.binarySearch(new int[]{1, 3, 5, 7}, 8)); //3
说明目标值处在数组中间时 middle 的一个情况:
- 当数组中有这个数时,middle 就是这个数的下标,我们可以不可以放在这个下标上?可以。
- 当数组中没有这个数时,下标为 middle 的数会大于目标值,我们可不可以放在这个下标上?可以
我们还可以看到当目标数小于数组中的所有数时,也是能够直接使用 middle 返回的,只有目标数大于数组中的所有数时,就不行, 8 把 7 往后挤,这个数组就不是递增的了。
我们可以发现,当目标数大于数组中的所有数时,在寻找 middle 的过程中是不会去移动右边界的,所以我们可以设置默认的返回的结果为数组的长度,然后只在移动右边界时才把 middle 赋值给返回结果。
运行的代码
public int searchInsert(int[] nums, int target) {
int l = 0,r = nums.length - 1;
int res = nums.length;
while(l<=r){
int middle = (l+r)/2;
if(nums[middle]<target){
// 因为当前数小于 target,l 收缩
l = middle + 1;
}else{
// 当前数大于 target,说明 target 可以放在这里
res = middle;
// 因为当前数大于 target,r 收缩
r = middle - 1;
}
}
return res;
}
最后
今天就到这里了。
这里是程序员徐小白,【每日算法】是我新开的一个专栏,在这里主要记录我学习算法的日常,也希望我能够坚持每日学习算法,不知道这样的文章风格您是否喜欢,不要吝啬您免费的赞,您的点赞、收藏以及评论都是我下班后坚持更文的动力。