给定一个排序数组(数组中无重复元素)和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。示例如下:
在数组中插入目标值有四种情况:
(1)目标值在数组中,直接返回下标;
(2)目标值不在数组中,需要插在头部;
(3)目标值不在数组中,需要插在中间;
(4)目标值不在数组中,需要插在最后;
下面通过暴力解法和二分查找来解决此题:
1.暴力解法
//Solution1 --暴力求解
int searchInsert(vector<int>& nums, int target) {
int l = nums.size();
if (target < nums[0]) return 0;
if (target > nums[l-1]) return l;
int i = 0;
while(nums[i] < target && i<l) {
i++;
}
return i;
}
暴力求解算法时间复杂度 O(n),空间复杂度O(1)。
2.二分查找
二分查找的基础条件为数组是有序数组,显然该题目满足要求。只要看到题目中给出的数组是有序数组,都可以想一想是否可以使用二分法。
下图为二分查找的思路:
二分查找代码要注意边界条件,对区间的定义想清楚。
(1)写法1:区间为[left,right]
//Solution2 --二分查找
int searchInsert(vector<int>& nums, int target) {
int n = num.size();
int left = 0;
int right = n-1;//定义target在左闭右闭的区间里,[left, right]
while(left<=right) {// 当left==right,区间[left, right]依然有效
int middle = (left+right)/2;
if (nums[middle] > target) {
right = middle-1;// target 在左区间,所以[left, middle - 1]
}
else if(nums[middle] < target) {
left = middle+1;
}
else{
return middle;
}
}
return right+1;
}
(2)写法2:区间为 [left,right)
//左闭右开区间二分查找
int searchInsert(vector<int>& nums, int target) {
int n = num.size();
int left = 0;
int right = n;//定义target在左闭右闭的区间里,[left, right)
while(left<right) {// 当left==right,区间[left, right)无效
int middle = (left+right)/2;
if (nums[middle] > target) {
right = middle;// target 在左区间,所以[left, middle)
}
else if(nums[middle] < target) {
left = middle + 1;
}
else{
return middle;
}
}
return right;
}
写二分查找时,要注意区分不同区间的写法。
二分查找时间复杂度为O(logn),空间复杂度为O(1)。