35. 搜索插入位置(C++)
题目
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 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 个严格大于 target 的元素,返回这个元素的下标;如果数组里所有的元素都严格小于 target,返回数组的长度 len。
代码如下:
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
//num记录是否出现了首位比target大的元素
int num = 0;
int tmp = 0;
for(int i=0;i<nums.size();i++){
if(nums[i]==target)
return i;
if(nums[i]>target && num==0){
tmp = i;
num = 1;
}
}
if(num==0)
return nums.size();
else
return tmp;
}
};
二分查找
在有序数组中查找插入元素的位置,显然可以使用二分查找。提供的思路是「排除法」,思路是:在循环的过程中,不断排除不需要的解,最后剩下的那个元素的位置就一定是插入元素的位置。
具体来说:
- 首先,插入位置有可能在数组的末尾,需要单独判断,此时返回数组的长度;
- 否则,根据示例和暴力解法的分析,插入的位置是大于等于 target 的第 1 个元素的位置。
因此,严格小于 target 的元素一定不是解,在循环体中将左右边界 left 和 right 逐渐向中间靠拢,最后 left 和 right 相遇,则找到了插入元素的位置。根据这个思路,可以写出如下代码。
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int len = nums.size();
//考虑数组为空的特殊情况
if(len==0)
return 0;
//考虑数据所有元素小于target的情况
if(nums[len-1]<target)
return len;
int left = 0;
int right = len-1;
while(left<right){
int mid = left + (right - left)/2;
//当nums[mid]严格小于目标元素时,肯定不是解
if(nums[mid]<target){
//下轮搜索区间 [mid + 1 , right]
left = mid + 1;
} else {
//搜索区间为上轮的反面 [left, mid]
right = mid;
}
}
return left;
}
};
注意代码是左动,所以中间值不需要进行变动,进行下取整即可。