LeetCode 热题 HOT — 在排序数组中查找元素的第一个和最后一个位置

127 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 11 天,点击查看活动详情

在排序数组中查找元素的第一个和最后一个位置

原题地址

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]

进阶:

你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?

示例 1:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:

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

提示:

  • 0 <= nums.length <=10510^5
  • 109-10^9<= nums[i] <=10910^9
  • nums 是一个非递减数组
  • 109-10^9<= target <=10910^9

思路分析

方法一

  1. 先通过数组的 findIndex 方法,找出 start 值;
  2. start-1,那么 返回 [-1, -1]
  3. 否则,遍历数组找出 end 值,每次找到跟 target 相同的,就把 end 赋值为对应的下标,最后返回 [start, end] 即可。

方法二

  1. 因为是升序数组,因此可以使用二分查找,先找出一个跟 target 一样的元素;
  2. 若二分查找未找到元素则返回 [-1, -1]
  3. 然后定义 start = mid, end = mid,向后搜索 end 值,向前搜索 start 值,最后返回 [start, end] 即可。

方法三

  1. 方法三整合了方法一和方法二;
  2. 使用 findIndex 找到 start 值;
  3. 然后向后搜索 end 值,返回 [start, end] 即可。

AC 代码

方法一

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var searchRange = function(nums, target) {
    const start = nums.findIndex(item => item === target)
    if(start === -1) return [-1, -1]
    let end = start
    nums.forEach((item, index) => {
        if(item === target) {
            end = index
        }
    })
    return [start, end]
};

结果:

  • 执行结果: 通过
  • 执行用时:72 ms, 在所有 JavaScript 提交中击败了20.87%的用户
  • 内存消耗:41.5 MB, 在所有 JavaScript 提交中击败了61.74%的用户
  • 通过测试用例:88 / 88

方法二

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var searchRange = function(nums, target) {
    let left = 0,
        right = nums.length - 1,
        mid
    while (left <= right) {
        mid = Math.ceil((left + right) / 2)
        if (nums[mid] === target) break
        if (nums[mid] > target) right = mid - 1
        else left = mid + 1
    }
    if (left > right) return [-1, -1]
    let start = mid,
        end = mid
      while (nums[start] === nums[start - 1]) start--
      while (nums[end] === nums[end + 1]) end++
      return [start, end]
};

结果:

  • 执行结果: 通过
  • 执行用时:60 ms, 在所有 JavaScript 提交中击败了76.75%的用户
  • 内存消耗:41.6 MB, 在所有 JavaScript 提交中击败了57.40%的用户
  • 通过测试用例:88 / 88

方法三

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var searchRange = function(nums, target) {
    const start = nums.findIndex(item => item === target)
    if (start === -1) return [-1, -1]
    let end = start
    while (end + 1 <= nums.length - 1 && nums[end] === nums[end + 1]) end++
    return [start, end]
};

结果:

  • 执行结果: 通过
  • 执行用时:56 ms, 在所有 JavaScript 提交中击败了89.74%的用户
  • 内存消耗:41.6 MB, 在所有 JavaScript 提交中击败了54.03%的用户
  • 通过测试用例:88 / 88

END