「LeetCode」35.搜索插入位置

192 阅读3分钟

「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战」。

题目描述🌍

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

请必须使用时间复杂度为 O(logn)O(log n) 的算法。

示例 1

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

示例 2

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

示例 3

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

示例 4

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

示例 5

输入: nums = [1], target = 0
输出: 0

提示:

  • 11 <= nums.length <= 10410^4
  • 104-10^4 <= nums[i] <= 10410^4
  • nums无重复元素升序排列数组
  • 104-10^4 <= target <= 10410^4

二分搜索插入(左闭右闭)🔎

解题思路

⭐该解法(左闭右闭)最关键的地方在于:为什么返回 left 而不是 right?!(针对情况 (2)

(1)如果要插入的值在数组中,那该值在数组中的位置就是搜索插入的位置,也就是「二分查找」过程。

(2)如果要插入的值不在数组中,那可以分开讨论,但要明确一点,使用左闭右闭插入的话,在最后一次的循环过程中一定会形成以下状态(执行到 int middle = left + (right - left) / 2;):

然后接下来就是判断语句,判断 target(图中 y) 与 nums[middle](图中 x) 的关系,分为两种情况:

  • y < x
  • y > x

一图胜千言。可见两种情况下,搜索插入的位置都是 left 指向的位置。

代码

Java

class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            int middle = left + (right - left) / 2;
            if (target < nums[middle]) {
                right = middle - 1;
            } else if (target > nums[middle]) {
                left = middle + 1;
            } else {
                return middle;
            }
        }
        // 两种情况下, left皆为结果!
        return left;
    }
}

C++

class Solution {
public:
    int searchInsert(vector<int> &nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        while (left <= right) {
            int middle = left + (right - left) / 2;
            if (target < nums[middle]) {
                right = middle - 1;
            } else if (target > nums[middle]) {
                left = middle + 1;
            } else {
                return middle;
            }
        }
        return left;
    }
};

时间复杂度:O(logn)O(logn),二分查找所需的时间复杂度。

空间复杂度:O(1)O(1)

二分搜索插入(左闭右开)🔍

解题思路

⭐该解法(左闭右开)就比较容易解决了,因为循环退出的时候 left 等于 right,且所以 return leftreturn right 都可以(针对待插入的值不存在于数组中这种情况)

但该搜索插入方法有一个特殊情况:当 target > nums[length - 1] 时,此时退出循环后,leftright 都为 length - 1,而应该返回的值为 length,所以该情况要排除。

代码

Java

class Solution 
    public int searchInsert(int[] nums, int target) {
        // 有且仅有 target > nums[length - 1] 这类情况对该(左闭右开)解法不适用,直接判断即可..
        int length = nums.length;
        if (target > nums[length - 1]) {
            return length;
        }

        int left = 0;
        int right = nums.length - 1;
        int middle;
        while (left < right) {
            middle = left + (right - left) / 2;
            if (target < nums[middle]) {
                right = middle;
            } else if (target > nums[middle]) {
                left = middle + 1;
            } else {
                return middle;
            }
        }

        // return left/right 都可以!
        return right;
    }
}

C++

class Solution {
public:
    int searchInsert(vector<int> &nums, int target) {
        int length = nums.size();
        // special circumstance
        if (target > nums[length - 1])
            return length;
        int left = 0;
        int right = length - 1;
        while (left < right) {
            int middle = left + (right - left) / 2;
            if (target < nums[middle]) {
                right = middle;
            } else if (target > nums[middle]) {
                left = middle + 1;
            } else {
                return middle;
            }
        }
        // left or right is ok
        return right;
    }
};

时间复杂度:O(logn)O(logn),二分查找所需的时间复杂度。

空间复杂度:O(1)O(1)

知识点🌓

本文如有不懂的地方,建议翻阅我上一篇发布的文章:带你领略「二分查找」的魅力

最后🌅

该篇文章为 「LeetCode」 系列的 No.9 篇,在这个系列文章中:

  • 尽量给出多种解题思路
  • 提供题解的多语言代码实现
  • 记录该题涉及的知识点

👨‍💻争取做到 LeetCode 每日 1 题,所有的题解/代码均收录于 「LeetCode」 仓库,欢迎随时加入我们的刷题小分队!