leetcode 35. Search Insert Position 简单
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-insert-position
题目描述
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.
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 <= 10^4
-10^4 <= nums[i] <= 10^4
nums contains distinct values sorted in ascending order.
-10^4 <= target <= 10^4
1.1. 思路
法一:暴力查找
通过从头到尾对数组进行遍历,寻找第一个大于等于target
的元素,并返回下标(由于原数组本身就按照递增排序)。
- 第一种情况:
target
小于第一个数组元素,即在数组所有元素之前; - 第二种情况:
target
在数组中:- a:
target
恰好等于其中元素; - b:
target
恰好大于前一个元素,小于后一个元素;
- a:
- 第三种情况:
target
大于所有数组元素。
法二:二分法
了解什么是二分法查找。
二分法查找,也称为折半法,是一种在有序数组中查找特定元素的搜索算法。
二分法查找的思路如下:
(1)首先,从数组的中间元素开始搜索,如果该元素正好是目标元素,则搜索过程结束,否则执行下一步。
(2)如果目标元素大于/小于中间元素,则在数组大于/小于中间元素的那一半区域查找,然后重复步骤(1)的操作。
(3)如果某一步数组为空,则表示找不到目标元素。
二分法查找的时间复杂度O(logn)。
1.2. 注意点
- 注意边界问题,通过暴力查找未果时,需要返回
nums.size()
表示应当插在最后的位置。 - 注意数组有序是使用二分法的前提,同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下表可能不是唯一的。
- 「只要看到题里给出的数组是有序数组,都可以想一想是否可以使用二分法。」
1.3. 代码
法一
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
for (int i = 0; i < nums.size(); i++) {
//对应第一二种情况 target在数组中可以找到位置
if (nums[i] >= target) {
return i;
}
}
//对应第三种情况 target只能插在最后
return nums.size();
}
};
法二
使用二分法时注意抓住循环不变量(指在循环过程中保持不变的量)。
接下来说明两种二分法的写法,即左闭右开和左闭右闭。
左闭右开(left < right)
即left
指向第一个元素,而right
指向最后一个元素的后一个。
(最后的情况时[left, right)
,且left < right
,故放在right
位置。)
class Solution {
public:
// 分别处理如下四种情况
// 目标值在数组所有元素之前 [0,0) return right
// 目标值等于数组中某一个元素 return middle
// 目标值插入数组中的位置 [left, right) ,return right 即可
// 目标值在数组所有元素之后的情况 [left, right),return right 即可
int searchInsert(vector<int>& nums, int target) {
int left = 0, right = nums.size();
//定义target在[left, right)中
while (left < right) {
int mid = (left + right) >> 1; //右移一位,即除以2
if (nums[mid] > target) { //表示target在左边部分[left, mid)
right = mid;
}
else if (nums[mid] == target) {
return mid;
}
else { //表示target在右边部分[mid+1, right)
left = mid + 1;
}
}
return right;
}
};
左闭右闭(left <= right)
即left
指向第一个元素,而right
指向最后一个元素。
(最后的情况时[left, right]
,且left = right
故放在right + 1
位置。)
class Solution {
public:
// 分别处理如下四种情况
// 目标值在数组所有元素之前 [0,-1] return right+1
// 目标值等于数组中某一个元素 return middle
// 目标值插入数组中的位置 [left, right] ,return right+1 即可
// 目标值在数组所有元素之后的情况 [left, right],return right+1 即可
int searchInsert(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
//定义target在[left, right]中
while (left <= right) {
int mid = (left + right) >> 1; //右移一位,即除以2
if (nums[mid] > target) { //表示target在左边部分[left, mid-1]
right = mid - 1;
}
else if (nums[mid] == target) {
return mid;
}
else { //表示target在右边部分[mid+1, right]
left = mid + 1;
}
}
return right + 1;
}
};
1.4. one more thing
在暴力解法中,以下算法与法一存在一些速度差异(我也不太清除)
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
for (int i = 0; i < nums.size(); i++) {
if (nums[i] == target) {
return i;
}
else if (nums[i] > target) {
return i;
}
}
return nums.size();
}
};
法一如下:
可能是比对次数导致。