大家好,我是河海哥,专注于后端,如果可以的话,想做一名code designer而不是普通的coder,一起见证河海哥的成长,您的评论与赞是我的最大动力,如有错误还请不吝赐教,万分感谢。一起支持原创吧!
1-1:题目
Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You must write an algorithm with O(log n) runtime complexity.
Example 1:
Input: nums = [1,3,5,6], target = 5
Output: 2
Example 2:
Input: nums = [1,3,5,6], target = 2
Output: 1
Example 3:
Input: nums = [1,3,5,6], target = 7
Output: 4
Example 4:
Input: nums = [1,3,5,6], target = 0
Output: 0
Example 5:
Input: nums = [1], target = 0
Output: 0
Constraints:
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums contains distinct values sorted in ascending order.
-104 <= target <= 104
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-insert-position
1-2:idea
在有序的数组中查找目标位置,logn很容易就想到,用二分查找,这里还有额外一个条件,如果说没有找到这个数字,就返回他该插入的地方,通过example可以看出,如果说,没有找到这个数,其实返回的位置就是数组第一个比target大的数的位置。整个代码的核心就在于,画个图:
试想如果是这种情况nums[mid] < target
,你该怎么办?该往右去逼近target,每次碰到这个条件的时候,mid就会往target处逼近一点,但是target永远大于nums[mid],所以只会得到比target小的那些数里面最大的那个数。所以这不是我们想要的,想要的是下面这种情况。
这种情况之下,就懂了呀,无限向左边逼近,那么要么得到target要么得到,第一个比target大的数字。
1-3:代码
public static int searchInsert2(int[] nums, int target) {
int n = nums.length;
int pos = n; // 边界的技巧
int left = 0;
int right = n - 1;
while (left <= right) {
int mid = (left + right) >> 1;
if (nums[mid] < target) {
left = mid + 1;
} else {
pos = mid;
right = mid - 1;
}
}
return pos;
}
上面的代码可以完美解决边界问题,比如target<nums[0]的时候,最后的值刚好就是0。另外pos初值就是n,如果是[1,2,3,4] 插5,pos还是n不会随着遍历而改变。那么这个代码找的就是第一个>=target的位置。
2022-2-2更:
另外一种写法
public int searchInsert3(int[] nums, int target) {
int n = nums.length;
if (target > nums[n - 1]) {
return n;
}
if (target < nums[0]) {
return 0;
} // 这两个判断可以直接筛掉边界的情况
int left = 0;
int right = n - 1;
while (left <= right) {
int mid = left + ((right - left) >> 1);
if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
// 最后left指的位置就是需要插入的位置了
return left;
}
1-4:总结
通过两张图可以完美理解了!