[前端]_一起刷leetcode34. 在排序数组中查找元素的第一个和最后一个位置

131 阅读3分钟

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

题目

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

给定一个按照升序排列的整数数组 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 <= 105
  • -109 <= nums[i] <= 109
  • nums 是一个非递减数组
  • -109 <= target <= 109

思路

  1. 首先先说一下暴力解法,我们可以通过一轮遍历找到当前的元素位置,然后加两个变量去存储对应开始位置和结束位置的索引,当遍历到当前元素的时候,如果开始位置的值为-1,就赋值覆盖,否则不做处理,结束位置的值每次覆盖掉即可,这样子遍历结束后只需要判断是否存在开始位置即可;
  2. 然后对于这道题目的话,我们要考虑到一个前置条件,是在排序数组中查找,那么我们在这种条件下,数据量大的情况下用二分查找的效率是最高的,所以我们可以用二分查找,迅速找到这个值,找到了之后,往前往后都走到值不相等时候即可。

具体而言可以分为以下三个步骤:

首先通过二分查找,快速找到一个跟当前元素值相等的索引

  • 如果找不到这个值的话,说明不存在这样子的一个元素,那么开始和结束值都返回-1即可;

  • 如果找到了这个值,那么我们分别以这个索引为起点,向左和向右查找,用whlie循环去判断,如果当前值往前或者往后走的值还是等于它本身,那么就继续走下去,直到走到尽头或者值不相等为止。

实现

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var searchRange = function(nums, target) {
    const index = findTargetIndex(nums, target);

    if (index === -1) return [-1, -1];

    let prevIndex = lastIndex = index;
    // 往左边走到尽头
    while (nums[prevIndex] === nums[prevIndex - 1]) {
        prevIndex--;
    }

    // 往右边走到尽头
    while (nums[lastIndex] === nums[lastIndex + 1]) {
        lastIndex++;
    }

    return [prevIndex, lastIndex];
};

// 朴实无华的二分查找
function findTargetIndex(nums, target) {
    let left = 0, right = nums.length - 1;

    while (left <= right) {
        const mid = Math.floor((left + right) / 2);

        if (nums[mid] === target) {
            return mid;
        } else if (nums[mid] > target) {
            right = mid - 1;     
        } else {
            left = mid + 1;
        }
    }

    return -1;
}

结果

image.png

总结

在遇到有序的数组中查找指定的值的时候,优先考虑二分查找,这可以算是这种题型的一种通用解题思路,当然具体实现过程可能是千变万化的,不要一昧的套用公式。

看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。