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

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

解析 LeetCode 34. 在排序数组中查找元素的第一个和最后一个位置:二分查找的灵活应用

在算法的学习中,LeetCode 34 题要求在排序数组里查找目标元素的起始和结束位置,且需满足 O(log⁡n)O(\log n)O(logn) 的时间复杂度,这使得二分查找成为解题的关键。以下将详细剖析解题思路、代码逻辑。

一、题目分析

在这里插入图片描述

(一)问题定义

给定非递减排序数组 nums 和目标值 target,找出 target 在数组中的起始索引和结束索引;若不存在,返回 [-1, -1] ,且算法需满足 O(log⁡n)O(\log n)O(logn) 时间复杂度。

(二)核心挑战

利用二分查找高效定位目标值的边界。因数组有序,常规二分可找目标值,但需改造以精准找第一个最后一个出现的位置。

二、原代码思路与问题

(一)思路概述

用一个循环,通过 leftKey 标记查找阶段:

  1. 查找左边界leftKeytrue 时,找到目标值后,更新左边界 topAndDown[0],并收缩右边界(right = mid - 1 ),继续找更左的目标值。
  2. 查找右边界:左边界找到后(left > right 触发 ),重置 leftrightleftKey 设为 false,再次二分,找到目标值后更新右边界 topAndDown[1],并收缩左边界(left = mid + 1 )。

(二)问题

  • 逻辑复杂:通过 left > right 切换查找阶段,增加理解和维护成本,且重置指针易出错。
  • 效率问题:虽整体是 O(log⁡n)O(\log n)O(logn),但代码逻辑不够简洁,可优化为两次独立二分(分别找左、右边界 )。

三、优化后的二分查找思路

(一)两次二分法

  1. 找左边界:在数组中找第一个大于等于 target 的位置,若该位置值不等于 target,则不存在;否则为左边界。
  2. 找右边界:找第一个大于 target 的位置,其前一个位置即为右边界(若存在目标值 )。

(二)实现逻辑

  • 左边界查找:初始化 left=0, right=nums.length,二分过程中,若 nums[mid] < targetleft = mid + 1;否则 right = mid 。最终 left 即为左边界(需验证是否越界及是否等于 target )。
  • 右边界查找:初始化 left=0, right=nums.length,二分过程中,若 nums[mid] <= targetleft = mid + 1;否则 right = mid 。最终 right - 1 即为右边界(需结合左边界验证 )。

四、优化代码实现

class Solution {public int[] searchRange(int[] nums, int target) {int leftBound = findLeftBound(nums, target);// 左边界不存在,直接返回 [-1, -1]if (leftBound == nums.length || nums[leftBound] != target) { return new int[]{-1, -1};}// 右边界是第一个大于 target 位置的前一个int rightBound = findRightBound(nums, target) - 1; return new int[]{leftBound, rightBound};}// 找第一个大于等于 target 的位置(左边界)private int findLeftBound(int[] nums, int target) {int left = 0, right = nums.length;while (left < right) {int mid = left + (right - left) / 2;if (nums[mid] < target) {left = mid + 1;} else {right = mid;}}return left;}// 找第一个大于 target 的位置(用于推导右边界)private int findRightBound(int[] nums, int target) {int left = 0, right = nums.length;while (left < right) {int mid = left + (right - left) / 2;if (nums[mid] <= target) {left = mid + 1;} else {right = mid;}}return left;}
}

(一)代码流程

  1. 找左边界:调用 findLeftBound,通过二分找到第一个 >= target 的位置。若该位置越界或值不等于 target,直接返回 [-1, -1]
  2. 找右边界:调用 findRightBound 找到第一个 > target 的位置,其前一个位置即为右边界(因数组有序,若存在目标值,右边界是最后一个 target 的索引 )。
  3. 返回结果:组合左、右边界,返回最终结果。

(二)关键逻辑

  • 二分边界处理findLeftBoundfindRightBound 均采用左闭右开区间(right = nums.length ),简化边界条件判断,避免死循环。
  • 结果验证:先验证左边界的有效性(是否为 target ),再推导右边界,确保结果正确。

五、复杂度分析

(一)时间复杂度

两次二分查找,每次时间复杂度为 O(log⁡n)O(\log n)O(logn),总体为 O(log⁡n)O(\log n)O(logn) ,满足题目要求。

(二)空间复杂度

仅使用常数级额外变量,空间复杂度为 O(1)O(1)O(1)

http://www.xdnf.cn/news/1345717.html

相关文章:

  • 当我们想用GPU(nlp模型篇)
  • 开源 python 应用 开发(十)音频压缩
  • 开源 python 应用 开发(十一)短语音转文本
  • ZKmall模块商城的跨境电商支付安全方案:加密与权限的双重防护
  • 数据结构 -- 树
  • STM32G4-比较器
  • 亚马逊老品怎么再次爆发流量?
  • 计算机内存中的整型存储奥秘、大小端字节序及其判断方法
  • 量子计算基础
  • 豆包AI PPT与秒出PPT对比评测:谁更适合你?
  • 树莓派安装pyqt5 opencv等库一些问题
  • 使用 YAML 文件,如何优雅地删除 k8s 资源?
  • 高并发用户数峰值对系统架构设计有哪些影响?
  • .java->.class->java 虚拟机中运行
  • 设计模式:抽象工厂模式
  • 实验二 Cisco IOS Site-to-Site Pre-share Key
  • 异质结3.0时代的降本提效革命:捷造科技设备技术创新与产业拐点分析
  • 高级SQL优化 | 告别 Hive 中 GROUP BY 的大 KEY 数据倾斜!PawSQL 自适应优化算法详解
  • Logstash——输出(Output)
  • 大视协作码垛机:颠覆传统制造,开启智能工厂新纪元
  • 【CV】OpenCV①——图形处理简介
  • 2025年视频大模型汇总、各自优势及视频大模型竞争焦点
  • 掌握设计模式--命令模式
  • WebRTC 结合云手机:释放实时通信与虚拟手机的强大协同效能
  • elasticsearch的使用
  • C#_高性能内存处理:Span<T>, Memory<T>, ArrayPool
  • vue vxe-gantt 甘特图自定义任务条样式模板 table 自定义插槽模板
  • Vue2 响应式系统设计原理与实现
  • 【Java并发编程】Java多线程深度解析:状态、通信与停止线程的全面指南
  • 多态(polymorphism)