34. 在排序数组中查找元素的第一个和最后一个位置
2026/5/11 22:55:40 网站建设 项目流程

这题本质上是:

用两次二分查找:

  • 第一次找target的最左位置

  • 第二次找target的最右位置

因为数组有序,所以可以O(log n)


一、核心思想

比如:

nums = [5,7,7,8,8,10] target = 8

我们想得到:

[3,4]

也就是:

  • 第一个 8 在哪里

  • 最后一个 8 在哪里


二、为什么普通二分不够

普通二分只能找到:

“某一个” 8

但题目要的是:

第一个8 和 最后一个8

所以要“偏向左找”和“偏向右找”。


三、找左边界

思想

即使找到 target:

nums[mid] == target

也不能立刻返回。

因为左边可能还有 target。

所以:

right = mid - 1

继续向左压缩。


过程示例

nums = [5,7,7,8,8,10] target = 8

初始:

left = 0 right = 5

第一次

mid = 2 nums[2] = 7

7 < 8

说明 target 在右边:

left = 3

第二次

left = 3 right = 5 mid = 4 nums[4] = 8

找到了!

但不能停。

因为左边可能还有 8。

继续往左缩:

right = 3

第三次

left = 3 right = 3 mid = 3 nums[3] = 8

继续左缩:

right = 2

结束。


最后:

left = 3

这就是左边界。


四、找右边界

和左边界完全相反。

找到 target 后:

left = mid + 1

因为还想看看右边有没有 target。


最后:

right

就是右边界。


五、完整代码(推荐记忆版)

class Solution { public int[] searchRange(int[] nums, int target) { int left = findLeft(nums, target); // 不存在target if (left == -1) { return new int[]{-1, -1}; } int right = findRight(nums, target); return new int[]{left, right}; } // 找左边界 public int findLeft(int[] nums, int target) { int left = 0; int right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] < target) { left = mid + 1; } else { right = mid - 1; } } // 越界 or 不存在 if (left >= nums.length || nums[left] != target) { return -1; } return left; } // 找右边界 public int findRight(int[] nums, int target) { int left = 0; int right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] <= target) { left = mid + 1; } else { right = mid - 1; } } return right; } }

六、最关键的区别(一定记住)

找左边界

nums[mid] < target

说明 target 在右边:

left = mid + 1

否则:

right = mid - 1

包括:

nums[mid] == target

也继续向左缩。


找右边界

nums[mid] <= target

说明:

即使等于 target,
也继续向右找。

所以:

left = mid + 1

七、一句话记忆

左边界

找到target也不停止,继续压左边

右边界

找到target也不停止,继续压右边

这就是这题的本质。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询