给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 1:
输入: [1,3,5,6], 5
输出: 2
示例 2:
输入: [1,3,5,6], 2
输出: 1
示例 3:
输入: [1,3,5,6], 7
输出: 4
思路1
数组的遍历&比大小?
本来想用for(num:nums)。但是这样就不知道怎么拿到数组的下标。
所以还是乖乖for(int i=0; i<position; i++)。
因为输入的数组是升序的。
再考虑到要插入的数如果是最大的,就直接放在数组最后面,这时候直接返回数组长度就好了。
所以初始化position的时候直接让他等于数组的长度。
然后在for循环里去找。
只要找到了目标位置就可以重新给position赋值,跳出循环。
代码1- 时间复杂度 O(n)
class Solution {
public int searchInsert(int[] nums, int target) {
int position=nums.length;
for(int i=0; i<position; i++){
while(target <= nums[i]){
position = i;
break;
}
}
return position;
}
}
解题思路2
昨天704.二分查找 的闭区间解法
参考Carl
代码2 O(log2n)
class Solution {
public int searchInsert(int[] nums, int target) {
//满足数组有序且不重复,使用二分法
int len = nums.length;
int left=0;
int right=len-1; //闭区间
while(left <= right){ //闭区间。==有意义
int mid = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
if(nums[mid] == target){
return mid;
}else if(nums[mid] < target){
left = mid + 1;
}else{
right = mid - 1;
}
}
// 分别处理如下四种情况
// 目标值在数组所有元素之前 [0, -1]
// 目标值等于数组中某一个元素 return middle;
// 目标值插入数组中的位置 [left, right],return right + 1
// 目标值在数组所有元素之后的情况 [left, right], return right + 1
return right + 1 ;
}
}
解题思路3
二分法右侧开区间
代码3
class Solution {
public int searchInsert(int[] nums, int target) {
//满足数组有序且不重复,使用二分法
int len = nums.length;
int left=0;
int right=len; //右侧开区间
while(left < right){ //右侧开区间。 等于号==没有意义
int mid = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
if(nums[mid] == target){
return mid;
}else if(nums[mid] < target){
left = mid + 1;
}else{
right = mid;
}
}
// 分别处理如下四种情况
// 目标值在数组所有元素之前 [0,0)
// 目标值等于数组中某一个元素 return middle
// 目标值插入数组中的位置 [left, right) ,return right 即可
// 目标值在数组所有元素之后的情况 [left, right),return right 即可
return right;
}
}
总结:二分法适用于有序存储。左右指针的区间定义,决定了左右区间的开和闭。如左右指针有意义,为闭区间,如指针无意义,为开区间。