一、题目描述
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 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
二、解题思路
暴力破解
遍历数组,当元素大于等于目标值的时候,返回其索引,假如目标值比数组所有元素都大,返回nums.length
public class Solution {
public int searchInsert(int[] nums, int target) {
int i=0;
while(i<nums.length){
if(nums[i]>=target){
return i;
}else{
i++;
}
}
return i;
}
}
复杂度分析
时间复杂度:O(n),一次遍历。
空间复杂度:O(1),只需要常数空间存放若干变量。
二分法
首先,插入位置有可能在数组的末尾(题目中的示例 3),需要单独判断。如果在数组的末尾,插入位置的下标就是数组的长度;
否则,根据示例和暴力解法的分析,插入位置的下标是 大于等于 target 的第 1个元素的位置。
因此,严格小于 target 的元素一定不是解,在循环体中将左右边界 left 和 right 逐渐向中间靠拢,最后 left 和 right 相遇,则找到了插入元素的位置。
public class Solution {
public int searchInsert(int[] nums, int target) {
int len = nums.length;
if (len == 0) {
return 0;
}
// 特判
if (nums[len - 1] < target) {
return len;
}
int left = 0;
int right = len - 1;
while (left < right) {
int mid = left + (right - left) / 2;
// 严格小于 target 的元素一定不是解
if (nums[mid] < target) {
// 下一轮搜索区间是 [mid + 1, right]
left = mid + 1;
} else {
// 下一轮搜索区间是 [left, mid]
right = mid;
}
}
return left;
}
}
复杂度分析
时间复杂度: O(logn) ,其中 n 为数组的长度,在循环一次排除一半,因此时间复杂度是对数级别的。
空间复杂度:O(1),只需要常数空间存放若干变量。
欢迎关注微信公众号【算法攻城师】