给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 1:
输入: [1,3,5,6], 5
输出: 2
示例 2:
输入: [1,3,5,6], 2
输出: 1
示例 3:
输入: [1,3,5,6], 7
输出: 4
示例 4:
输入: [1,3,5,6], 0
输出: 0
——题目难度:简单
分析
有序数组中查找插入元素的位置,二分查找显然适用。大致思路是:在循环的过程中,不断排除不需要的解,最后剩下的那个元素的位置就一定是插入元素的位置。也就是使用二分法来达到「排除法」的效果。
1.当 nums 中没有元素时,直接返回 0
2.当目标值大于 nums 里的最大值,则说明需要将其插入到数组的末尾,所以直接返回 nums.size()
3.当1 ,2的情况都不符合,那就说明需要查找的目标索引在区间 [0, nums.size() - 1] 内
- 如果 target > nums[mid],因为严格小于 target 的元素一定不是解,所以可以排除掉区间 [left, mid] ,也就是可以设置下一轮的搜索区间为 [mid + 1, right]
- 如果 target <= nums[mid] ,如果 target == nums[mid] 的话,说明 mid 就是目标索引、如果 target < nums[mid] 的话,mid 则有可能是目标索引(当nums中没有target时)。综上所述,当 target <= nums[mid] 时,因为严格大于等于 target 的元素有可能是解,所以可以设置下一轮的搜索区间为 [left, mid],也就是可以排除掉区间 [mid + 1, right]。
- 这样不断缩小区间后,肯定会缩小到只有一个元素的区间的时候(left == right),也就是找到了目标索引(是left,因为计算 mid 是下取整)
4.直接返回 left 即可。
-下面代码(C++)
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
if (n == 0) return 0;
/*如果目标值大于 nums 里的最大值,则将其插入到数组的末尾*/
if (target > nums[n-1]) return n;
/*将在区间 [0, n - 1] 内查找目标索引*/
int left = 0, right = n - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (target > nums[mid]) { //严格小于 target 的元素一定不是解
//下一轮搜索区间是 [mid + 1, right]
left = mid + 1;
} else { //严格大于等于 target 的元素有可能是解
//下一轮搜索区间是 [left, mid]
right = mid;
}
}
return left;
}
};
C语言实现的代码 和 上述的分析思路有所不同,但其二分法的核心不变。
-下面代码(C语言)
//二分法
int searchInsert(int* nums, int numsSize, int target){
int left = 0, right = numsSize-1,middle;
while(right>=left)
{
middle = (left+right)/2;
if(nums[middle]==target){
return middle;
}else if(nums[middle]>target){
right = middle-1;
}else{
left = left+1;
}
}
return left;
}