LeetCode - [35] 搜索插入位置|刷题打卡

261 阅读2分钟

题目描述:

原题地址

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

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

示例一

输入: [1,3,5,6], 5
输出: 2

示例二

输入: [1,3,5,6], 2
输出: 1

示例三

输入: [1,3,5,6], 7
输出: 4

示例三

输入: [1,3,5,6], 0
输出: 0

思路分析

考虑这个插入的位置 pos\textit{pos},它成立的条件为:

nums[pos1]<targetnums[pos]\textit{nums}[pos-1]<\textit{target}\le \textit{nums}[pos]

其中 nums\textit{nums} 代表排序数组。由于如果存在这个目标值,我们返回的索引也是 pos\textit{pos},因此我们可以将两个条件合并得出最后的目标:「在一个有序数组中找第一个大于等于 target\textit{target} 的下标」。

但是这题还要注意边界情况

  • 目标值在数组所有元素之前
  • 目标值等于数组中某一个元素
  • 目标值插入数组中的位置
  • 目标值在数组所有元素之后

image.png

这四种情况确认清楚了,就可以尝试解题了。

暴力法

这个就不多说了,直接上代码。

AC代码

fun searchInsert(nums: IntArray, target: Int): Int {
        for (i in 0 until nums.size) {
            // 分别处理如下三种情况
            // 目标值在数组所有元素之前
            // 目标值等于数组中某一个元素  
            // 目标值插入数组中的位置 
            if (nums[i] >= target) {
                // 一旦发现大于或者等于target的num[i],那么i就是我们要的结果
                return i
            }
        }
        // 目标值在数组所有元素之后的情况 
        return nums.size //如果target是最大的,或者 nums为空,则返回nums的长度
    }

复杂度分析

时间复杂度:O(n)\mathcal{O}(n)

空间复杂度:O(1)\mathcal{O}(1)

二分查找

要注意这道题目的前提是数组是有序数组,这也是使用 二分查找 的基础条件。

以后只要看到题里给出的数组是有序数组,都可以想一想是否可以使用二分法。

同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下表可能不是唯一的。

本题整体思路和普通的二分查找几乎没有区别,

  1. 先设定左侧下标 left 和右侧下标 right,再计算中间下标 mid
  2. 每次根据 nums[mid]target 之间的大小进行判断,相等则直接返回下标,nums[mid] < targetleft 右移,nums[mid] > targetright 左移
  3. 查找结束如果没有相等值则返回 left,该值为插入位置

AC代码

class Solution {
    fun searchInsert(nums: IntArray, target: Int): Int {
        var left =0
        var right = nums.size - 1 // 定义target在左闭右闭的区间里,[left, right] 
        while (left <= right) { // 当left==right,区间[left, right]依然有效
            var mid = (left + right) / 2 // 防止溢出 等同于(left + right)/2
            if (nums[mid] == target) {
                return mid // target 在左区间,所以[left, middle - 1]
            } else if (nums[mid] < target ) {
                left = mid +1 // target 在右区间,所以[middle + 1, right]
            } else { // nums[middle] == target
                right = mid +1
            }
        }
        // 分别处理如下四种情况
        // 目标值在数组所有元素之前  [0, -1]
        // 目标值等于数组中某一个元素  return middle;
        // 目标值插入数组中的位置 [left, right],return  right + 1
        // 目标值在数组所有元素之后的情况 [left, right], return right + 1
        return left
    }
}

复杂度分析

时间复杂度:O(logn){\mathcal{O}}(logn)

空间复杂度:O(1){\mathcal{O}}(1)

参考

官解 搜索插入位置
35.搜索插入位置:【彻底讲透二分法】

总结

这个说实话我一开始只想到了暴力解法,毕竟也才入门,算法基础这两天边刷边补。 然后看了题解,尝试使用了二分法

然后理论上来说
暴力解法 时间复杂度O(n)\mathcal{O}(n)
二分法解法 时间复杂度O(logn){\mathcal{O}}(logn)

但那都是理论上的,世事无绝对,暴力解题 不一定时间消耗就非常高,关键看实现的方式,就像是二分查找时间消耗不一定就很低,是一样的。

我用二分法提交了2次都是 超出时间限制 - -

再接再厉。

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情