题目描述

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

示例 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

解题思路

2.1 暴力破解

遍历数组,当元素大于等于目标值的时候,返回其索引,假如目标值比数组所有元素都大,返回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),只需要常数空间存放若干变量。

2.2 二分法

首先,插入位置有可能在数组的末尾(题目中的示例 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),只需要常数空间存放若干变量。

欢迎关注微信公众号【算法攻城师】

Leetcode No.35 搜索插入位置_搜索