leetcode编号35:搜索插入位置
题目描述:给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 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
思路
考虑插入位置的四种情况:
① 目标值在所有元素之前。
② 目标值等于数组中某一个元素。
③ 目标值在数组中两个元素之间。
④目标值在所有元素后面。
解法
暴力解法
class solution
{
public:
int searchInsert(vector<int>& nums, int target)
{
for (int i = 0; i < nums.size(); i++)
{
if (nums[i] > target)
{
//情况①②③
return i;
}
}
//情况④
return nums.size();
}
};
时间复杂度:O(n)
空间复杂度:O(1)
二分法
注意题目描述,给定的是一个有序的数组,以后刷题看到是有序数组时就可以考虑是否可以用二分法了。
同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下表可能不是唯一的。
class solution
{
public:
int searchInsert(vector<int>& nums, int target)
{
int size = nums.size();
//定义边界
int left = 0;
int right = size - 1;
//坚持左闭右闭的原则
while (left <= right)
{
int mid = left + (right - left) / 2; //这里不直接用(right - left) / 2 是为了防止溢出。例right = 5, left = 4 和 right = 2,left = 1 对比一下即可。
if (target > nums[mid])
{
//因为数组有序,大于就往mid 右边搜索
//改变区间范围,始终坚持区间左闭右闭原则
left = mid + 1;
}
else if (target < nums[mid])
{
//同理小于往左
right = mid - 1;
}
else
{
//nums[ mid] == target
return mid;
}
//while 循环里我们处理了情况①②③
}
//情况④
return right + 1; //这里为什么用right返回,注意right在while 中是可能变动的。因为数组有序,所以right 变动的情况(即target < nums[mid]),所以不可能出现情况④了。
}
};
可以再试试【左闭右开】的二分法写法。
总结
在涉及边界变动时,坚持循环不变量原则(即上面说的在区间变动时坚持左闭右闭区间),很多细节问题自然而然的就知道如何处理了。