当前位置: 首页 > article >正文

一起学习LeetCode热题100道(65/100)

65.在排序数组中查找元素的第一个和最后一个位置(学习)

给你一个按照非递减顺序排列的整数数组 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.searchRange函数的目的是在一个按非递减顺序排列的整数数组nums中查找一个目标值target的起始和结束索引(即左边界和右边界)。如果target不存在于数组中,则返回[-1, -1]。

二、辅助函数findBound
首先,我们定义了一个辅助函数findBound,它接收三个参数:nums(整数数组)、target(目标值)和isFirst(一个布尔值,指示我们是在查找第一个等于target的元素(true)还是最后一个等于target的元素(false))。

1.参数初始化:left被初始化为0(数组的起始索引),right被初始化为nums.length - 1(数组的末尾索引),result被初始化为-1,用于存储找到的边界索引。
2.循环条件:当left <= right时,继续循环。这是典型的二分查找循环条件。
3.中间索引计算:mid = Math.floor((left + right) / 2),计算当前搜索区间的中间索引。
4.条件判断:
4.1.如果nums[mid] === target,说明找到了一个等于target的元素。此时,根据isFirst的值,我们决定是向左搜索(right = mid - 1)以查找第一个等于target的元素,还是向右搜索(left = mid + 1)以查找最后一个等于target的元素。同时,更新result为mid,因为我们找到了一个可能的边界。
4.2.如果nums[mid] < target,说明目标值在mid的右侧(或在mid处但尚未找到),因此将left更新为mid + 1以继续向右搜索。
4.3.如果nums[mid] > target,说明目标值在mid的左侧,因此将right更新为mid - 1以继续向左搜索。
5.返回值:当循环结束时,如果找到了等于target的元素,result将被更新为那个元素的索引;否则,result将保持为初始值-1。

三、searchRange函数的工作过程
1.检查空数组:如果nums为空,则直接返回[-1, -1],因为没有元素可以查找。
2.查找左边界:调用findBound(nums, target, true)来查找第一个等于target的元素的索引,并将其存储在leftBound中。
3.检查左边界是否存在:如果leftBound为-1,说明没有找到等于target的元素,直接返回[-1, -1]。
4.查找右边界:调用findBound(nums, target, false)来查找最后一个等于target的元素的索引,并将其存储在rightBound中。由于我们已经知道至少存在一个等于target的元素(因为leftBound不是-1),所以不需要再对rightBound进行额外的检查。
5.返回结果:返回一个包含左边界和右边界索引的数组[leftBound, rightBound]。

var searchRange = function (nums, target) {
    if (nums.length === 0) return [-1, -1];

    // 查找左边界  
    let leftBound = findBound(nums, target, true);
    if (leftBound === -1) return [-1, -1]; // 如果没有找到左边界,说明数组中不存在目标值  

    // 查找右边界(注意这里不需要再减去1,因为findBound已经为我们找到了最后一个等于target的索引)  
    let rightBound = findBound(nums, target, false);
    // 但需要确保rightBound不小于leftBound,以防止出现错误的情况(虽然按题目要求,这种情况不会发生)  
    rightBound = Math.max(leftBound, rightBound);

    // 实际上,由于题目保证了数组是按非递减顺序排列的,并且我们找到了左边界,  
    // 所以rightBound一定不会小于leftBound,上面的Math.max是多余的。  
    // 但为了严谨性,我还是保留了这个检查(尽管在正常情况下它不会被触发)。  

    return [leftBound, rightBound];

    // 辅助函数:找到第一个(或最后一个)等于target的元素的索引  
    function findBound(nums, target, isFirst) {
        let left = 0, right = nums.length - 1;
        let result = -1;

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

            if (nums[mid] === target) {
                result = mid;
                if (isFirst) {
                    right = mid - 1; // 查找第一个等于target的元素  
                } else {
                    left = mid + 1; // 查找最后一个等于target的元素  
                }
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        return result;
    }
};

http://www.kler.cn/a/289300.html

相关文章:

  • LeetCode【0033】搜索旋转排序数组
  • 什么时候需要复写hashcode()和compartTo方法
  • ML 系列: 第 24 节 — 离散概率分布(泊松分布)
  • uniapp 设置安全区域
  • WPF中MVVM工具包 CommunityToolkit.Mvvm
  • 【leetcode练习·二叉树】用「分解问题」思维解题 II
  • 数据结构基本知识
  • Rust: Web框架Axum和Rest Client协同测试
  • 从 Oracle 到 TiDB 丨数据库资源评估指南
  • CUDA与TensorRT学习一:并行处理与GPU体系架构
  • 名城优企游学活动走进龙腾半导体:CRM助力构建营销服全流程体系
  • nginx部署前段VUE项目
  • wsl2 无法上网解决方法
  • 文本文件完整性判断-加密
  • Python中排序算法之冒泡排序
  • Soul Machines——AI生成虚拟主播或虚拟人,模拟真人交互
  • 后端MVC三层架构,Mybatis ,雪花算法生成唯一id
  • 『功能项目』销毁怪物蛋的Shaders消融特效【17】
  • SpringDataJPA系列(5)@Query应该怎么用?
  • QT connect的使用
  • 算法练习题11:单词出现次数
  • Android kotlin使用Netty网络框架实践(客户端、服务端)
  • 新版Pycharm的Available Packages里面为空,新版没有Manage Repositories功能,如何解决
  • OpenGL/GLUT实践:弹簧-质量-阻尼系统模拟摆动的绳子和布料的物理行为(电子科技大学信软图形与动画Ⅱ实验)
  • 《React Hooks:让你的组件更灵活》
  • Android之电量优化