前端刷题路-Day72:搜索插入位置(题号35)

213 阅读2分钟

这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战

搜索插入位置(题号35)

题目

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

请必须使用时间复杂度为 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

提示:

  • 1 <= nums.length <= 104
  • -104 <= nums[i] <= 104
  • nums 为无重复元素的升序排列数组
  • -104 <= target <= 104

链接

leetcode-cn.com/problems/se…

解释

这题啊,这题是简我击(简单题我重拳出击)。

如果不看题目上的强制要求:

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

那么实际操作会非常简单,直接遍历一次就好,如果运气好甚至都不用走完,但这样做的时间复杂度就是O(n)了,并不符合题目的规范,这个o(nlogn)就明显告诉我们使用二分去操作。

其实这个二分只要最简单的二分就好了,每次只需要根据mid来更新leftright的位置,直到left大于right就结束,所以while的循环条件就是left <= right

说到这就再看看二分的基本原理吧,首先这是一个升序的数组,且没有重复项。

那么mid就是左指针和右指针和的一半,然后用地板除取整数,注意这里不是四舍五入,就是单纯的取整数部分,小数部分不要。这里不要小数部分是有原因的,因为后续赋值的时候会在mid的基础上+1或者-1,如果四舍五入了,就会出现增加两个数字的情况,这是不可取的。

取到mid之后,如果mid比目标值大,那就证明目标值在数组的前半段,将right赋值为mid-1即可;如果mid比目标值小,那证明目标值在数组后半段,此时将left赋值为mid+1即可。为什么要+1呢?因为mid已经被排除在外了,在将mid带入存在区间没有意义,更重要的是因为循环终止条件是left <= right,如果不对mid进行+1-1操作,left永远不会比right大,那么此时循环永远不会终止,死循环也就产生了。

回到题目本身,为什么最后的left值就是target的位置呢?有两种情况:

  • target存在于数组中

    循环会一直走到right+1的那一部分,此时right被赋值给mid-1right会不断变小,直到right < left,此时的left就会是答案了

  • target不存在于数组中

    不存在于数组中就简单一些了,只需要定位到一个位置,此时的左指针应该比target小,右指针应该比target大,那么此时的左指针自然就是target应该插入的位置了

说了这么多,直接看看代码吧

自己的答案(双指针)

 var searchInsert = function(nums, target) {
  let left = 0, right = nums.length - 1
  while (left <= right) {
    const mid = ~~((left + right) / 2)
    if (nums[mid] < target) {
      left = mid + 1
    } else {
      right = mid - 1
    }
  }
  return left
};

跟上面说的思路一样,一直循环到终止条件的位置,没啥可说的。

官方的解答(双指针)

var searchInsert = function(nums, target) {
    const n = nums.length;
    let left = 0, right = n - 1, ans = n;
    while (left <= right) {
        let mid = ((right - left) >> 1) + left;
        if (target <= nums[mid]) {
            ans = mid;
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }
    return ans;
};

官方答案感觉有点多此一举的意思,非要存个ans变量,可能是处于代码理解层面的优化,这里就不得而知了。



PS:想查看往期文章和题目可以点击下面的链接:

这里是按照日期分类的👇

前端刷题路-目录(日期分类)

经过有些朋友的提醒,感觉也应该按照题型分类
这里是按照题型分类的👇

前端刷题路-目录(题型分类)