leetcode每天一题:【搜索插入位置】(简单)

170 阅读1分钟

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

题目描述

leetcode题目地址

给一个排好序的数组,和一个目标值,在数组中找该目标值,如果存在,则返回该索引,否则返回它存在这个数组应该存在的位置的索引。

举个例子:

arr: [2,3,5]
目标值: 5
返回: 2

arr: [2,3,5]
目标值: 2
返回: 0

arr: [2,3,5]
目标值: 4
返回: 2

思路分析

常规遍历

根据已知条件,数组是排好序的,我们可以先判断目标值是不是在数组的范围内。

如果不在,则无需遍历,直接返回了。

所以我们先让它跟数组的第一个和最后一个数比较

  1. 如果目标值小于第一个数,则直接返回0即可(因为它会插入数组的开头)。
  2. 如果目标值大于最后一个数,则直接返回数组的长度即可(因为它会插入数组的结尾)。

如果在的话,则需要遍历判断

  1. 如果遍历的数和目标值相等,则直接返回当前索引。
  2. 如果目标值比当前遍历的数大,并且小于下一个遍历的数,则证明目标值并不在数组中,返回当前的索引加一即可(因为它会插入当前遍历的数的下一个数)。

代码如下:

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var searchInsert = function (nums, target) {
  if (nums[0] > target) return 0
  if (nums[nums.length - 1] < target) return nums.length
  for (let i = 0; i < nums.length; i++) {
    if (nums[i] === target) return i
    if (nums[i] <= target && target <= nums[i + 1]) {
      return i + 1
    }
  }
};

image.png

上面的时间复杂度是O(n),

那你能使用时间复杂度为 O(log n) 的算法吗?

可以的,可以使用二分法。

二分法

这个是利用首尾索引当作左右的索引,折中取中间的值,和目标值比较,如果目标值大,则把中间的索引加一赋值给左边,如果目标值小,则把中间的索引减一赋值给右边。然后如果和目标值相等,则直接返回中间的索引。

不相等继续折中取中间值,直到左边索引大于右边才退出while循环,然后返回左边索引,或者中间值等于目标值才返回。

代码如下:

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

image.png