Loading

leetcode 35. Search Insert Position 简单

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-insert-position

题目描述

Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.

Example 1:

Input: nums = [1,3,5,6], target = 5
Output: 2

Example 2:

Input: nums = [1,3,5,6], target = 2
Output: 1

Example 3:

Input: nums = [1,3,5,6], target = 7
Output: 4

Example 4:

Input: nums = [1,3,5,6], target = 0
Output: 0

Example 5:

Input: nums = [1], target = 0
Output: 0

Constraints:

1 <= nums.length <= 10^4
-10^4 <= nums[i] <= 10^4
nums contains distinct values sorted in ascending order.
-10^4 <= target <= 10^4

1.1. 思路

法一:暴力查找

通过从头到尾对数组进行遍历,寻找第一个大于等于target的元素,并返回下标(由于原数组本身就按照递增排序)。

  • 第一种情况:target小于第一个数组元素,即在数组所有元素之前;
  • 第二种情况:target在数组中:
    • a:target恰好等于其中元素;
    • b:target恰好大于前一个元素,小于后一个元素;
  • 第三种情况:target大于所有数组元素。

法二:二分法

了解什么是二分法查找。

二分法查找,也称为折半法,是一种在有序数组中查找特定元素的搜索算法。
二分法查找的思路如下:
(1)首先,从数组的中间元素开始搜索,如果该元素正好是目标元素,则搜索过程结束,否则执行下一步。
(2)如果目标元素大于/小于中间元素,则在数组大于/小于中间元素的那一半区域查找,然后重复步骤(1)的操作。
(3)如果某一步数组为空,则表示找不到目标元素。
二分法查找的时间复杂度O(logn)。

1.2. 注意点

  • 注意边界问题,通过暴力查找未果时,需要返回nums.size()表示应当插在最后的位置。
  • 注意数组有序是使用二分法的前提,同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下表可能不是唯一的。
  • 「只要看到题里给出的数组是有序数组,都可以想一想是否可以使用二分法。」

1.3. 代码

法一

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        for (int i = 0; i < nums.size(); i++) {
            //对应第一二种情况 target在数组中可以找到位置
            if (nums[i] >= target) {
                return i;
            }
        }
        //对应第三种情况 target只能插在最后
        return nums.size();
    }
};

法二

使用二分法时注意抓住循环不变量(指在循环过程中保持不变的量)。

接下来说明两种二分法的写法,即左闭右开和左闭右闭。

左闭右开(left < right)

left指向第一个元素,而right指向最后一个元素的后一个。
(最后的情况时[left, right),且left < right,故放在right位置。)

class Solution {
public:
    // 分别处理如下四种情况
    // 目标值在数组所有元素之前 [0,0) return right
    // 目标值等于数组中某一个元素 return middle
    // 目标值插入数组中的位置 [left, right) ,return right 即可
    // 目标值在数组所有元素之后的情况 [left, right),return right 即可
    int searchInsert(vector<int>& nums, int target) {
        int left = 0, right = nums.size();
        //定义target在[left, right)中
        while (left < right) {
            int mid = (left + right) >> 1;	//右移一位,即除以2
            if (nums[mid] > target) {	//表示target在左边部分[left, mid)
                right = mid;
            }
            else if (nums[mid] == target) {
                return mid;
            }
            else {	//表示target在右边部分[mid+1, right)
                left = mid + 1;
            }
        }
        return right;
    }
};

左闭右闭(left <= right)

left指向第一个元素,而right指向最后一个元素。
(最后的情况时[left, right],且left = right故放在right + 1位置。)

class Solution {
public:
    // 分别处理如下四种情况
    // 目标值在数组所有元素之前 [0,-1] return right+1
    // 目标值等于数组中某一个元素 return middle
    // 目标值插入数组中的位置 [left, right] ,return right+1 即可
    // 目标值在数组所有元素之后的情况 [left, right],return right+1 即可
    int searchInsert(vector<int>& nums, int target) {
        int left = 0, right = nums.size() - 1;
        //定义target在[left, right]中
        while (left <= right) {
            int mid = (left + right) >> 1;	//右移一位,即除以2
            if (nums[mid] > target) {	//表示target在左边部分[left, mid-1]
                right = mid - 1;
            }
            else if (nums[mid] == target) {
                return mid;
            }
            else {	//表示target在右边部分[mid+1, right]
                left = mid + 1;
            }
        }
        return right + 1;
    }
};

1.4. one more thing

在暴力解法中,以下算法与法一存在一些速度差异(我也不太清除)

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] == target) {
                return i;
            }
            else if (nums[i] > target) {
                return i;
            }
        }
        return nums.size();
    }
};

法一如下:

可能是比对次数导致。

posted @ 2021-03-14 20:45  seigann  阅读(69)  评论(0)    收藏  举报