news 2026/5/5 3:07:26

【LeetCode 刷题笔记】34. 在排序数组中查找元素的第一个和最后一个位置 | 二分查找经典刷题题解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【LeetCode 刷题笔记】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]

二、解题思路

  • 题目明确要求时间复杂度为O(log n),暴力遍历(O(n))不符合要求,必须使用二分查找
  • 核心需求拆解:找到目标值的左边界(第一个等于target的位置)右边界(最后一个等于target的位置)
  • 优化思路:复用同一个“找下界”的二分函数,避免写两套逻辑:
    1. 左边界:直接调用lowBound(nums, target),得到第一个大于等于target的索引;
    2. 右边界:调用lowBound(nums, target + 1)得到第一个大于等于target+1的索引,再减1,即为最后一个等于target的索引;
    3. 先判断左边界是否有效(是否存在target),不存在则直接返回[-1,-1]

三、代码实现(Java)

class Solution {
public int[] searchRange(int[] nums, int target) {
// 1. 找目标值的左边界(第一个等于target的位置)
int start = lowBound(nums, target);
// 2. 判断目标值是否存在:左边界超出数组或对应元素不等于target,说明不存在
if (start == nums.length || nums[start] != target) {
return new int[]{-1, -1};
}
// 3. 找右边界:找target+1的下界,再减1,即为最后一个等于target的位置
int end = lowBound(nums, target + 1) - 1;
return new int[]{start, end};
}

/**
* 找数组中第一个大于等于target的元素的索引(下界函数)
* @param nums 非递减排序数组
* @param target 目标值
* @return 第一个大于等于target的索引,不存在则返回nums.length
*/
public int lowBound(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
int mid = 0;
// 闭区间二分查找,保证遍历所有元素
while (left <= right) {
// 计算中间位置,避免low + high直接相加导致int溢出
mid = left + (right - left) / 2;
if (nums[mid] >= target) {
// mid值大于等于target,左边界在左侧(含mid),更新右边界
right = mid - 1;
} else {
// mid值小于target,左边界在右侧(不含mid),更新左边界
left = mid + 1;
}
}
// 循环结束时left即为第一个大于等于target的位置
return left;
}
}

四、核心笔记 & 易错点解析

1. 二分查找中“等于”情况的合并逻辑

- 正常二分查找中,若nums[mid] > target,需要向左查找(right = mid - 1);

- 在找下界(第一个大于等于target的位置)时,nums[mid] == target也需要向左查找(因为左侧可能存在更小的索引等于target),因此将==>的情况合并处理,统一更新right = mid - 1

- 若要找上界(最后一个等于target的位置),则nums[mid] == target需要向右查找,此时==应与<的情况合并,更新left = mid + 1

- 无需死记硬背“等于和谁合并”,只需根据找上下界的需求,确定==时该往哪个方向缩小区间,再合并即可。

2. 目标值不存在的三种情况分析

调用lowBound函数后,若目标值不在数组中,会出现三种情况:

- 数组所有元素都小于target:此时left = nums.length(超出数组范围),right = nums.length - 1,需通过start == nums.length判断不存在;

- 数组所有元素都大于target:此时left = 0,但nums[left] != target,需通过nums[start] != target判断不存在;

- 数组中部分元素小于target、部分大于target:此时right是小于target的最大值的索引,left是大于target的最小值的索引,同样通过nums[start] != target判断不存在;

因此,调用lowBound后,必须加上start == nums.length || nums[start] != target的判断,才能确定target是否存在。

3. 循环结束的边界特性

由于while (left <= right)的循环条件,无论==与谁合并在一起,循环结束时一定满足right < left,且right + 1 == left

- 若target存在于数组中,left是目标值的下界,right是小于target的最大元素的索引;

- 若target不存在,left是target应该插入的位置,right是小于target的最大元素的索引;

这个特性是后续计算右边界(lowBound(nums, target + 1) - 1)的核心依据。


五、复杂度分析

-时间复杂度O(log n),两次调用lowBound函数,每次都是二分查找,时间复杂度为O(log n),两次调用仍为O(log n),符合题目要求。

-空间复杂度O(1),仅使用了常数级别的额外变量,没有使用额外的辅助空间。


六、总结

- 这道题的核心是利用“找下界”的二分函数,同时解决目标值左右边界的查找问题,避免了写两套二分逻辑,代码更简洁易维护。

- 关键在于理解二分查找中==情况的合并逻辑,以及循环结束后leftright的边界特性。

- 必须先判断目标值是否存在,再计算右边界,避免数组越界或返回错误结果。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/5 3:04:27

Happy Island Designer终极指南:5步打造你的梦想岛屿规划

Happy Island Designer终极指南&#xff1a;5步打造你的梦想岛屿规划 【免费下载链接】HappyIslandDesigner "Happy Island Designer (Alpha)"&#xff0c;是一个在线工具&#xff0c;它允许用户设计和定制自己的岛屿。这个工具是受游戏《动物森友会》(Animal Crossi…

作者头像 李华
网站建设 2026/5/5 2:59:58

告别重复配置:用快马AI一键生成工程化gstack项目底座,效率倍增

作为一个经常需要搭建新项目的前端开发者&#xff0c;我深刻体会到每次从零开始配置工程化环境的痛苦。特别是使用gstack这类技术栈时&#xff0c;光是安装依赖、配置插件、设置代码规范就要耗费大半天时间。最近发现InsCode(快马)平台的AI生成功能&#xff0c;能直接把这种重复…

作者头像 李华
网站建设 2026/5/5 2:57:09

Python自动化脚本实战:路由器签到与GitHub Actions部署指南

1. 项目概述与核心价值最近在折腾一些自动化脚本&#xff0c;发现一个挺有意思的项目&#xff0c;叫millylee/anyrouter-check-in。乍一看名字&#xff0c;可能很多朋友会有点懵&#xff0c;这“anyrouter”和“check-in”组合在一起是啥意思&#xff1f;其实&#xff0c;这是一…

作者头像 李华
网站建设 2026/5/5 2:50:44

TRIT框架:多语言长文本处理的创新解决方案

1. TRIT框架核心设计解析多语言长文本处理一直是NLP领域的硬骨头。传统方法要么受限于单任务优化&#xff0c;要么难以应对跨语言的语义一致性挑战。我们团队开发的TRIT框架&#xff08;Translation-augmented Reasoning and Inference Transformer&#xff09;尝试从底层架构层…

作者头像 李华
网站建设 2026/5/5 2:50:32

Shell脚本工具集:打造高效命令行工作流与自动化实践

1. 项目概述&#xff1a;一个为开发者打造的“瑞士军刀”脚本库如果你和我一样&#xff0c;经常在命令行里折腾&#xff0c;那你肯定遇到过这样的场景&#xff1a;想快速处理一个文本文件&#xff0c;得临时写个Python脚本&#xff1b;想批量重命名一堆文件&#xff0c;得去网上…

作者头像 李华