题目

在排序数组中查找元素的第一个和最后一个位置 - 图1

解题思路

1、分析二分查找代码时,不要出现 else,全部展开成 else if 方便理解。
2、注意「搜索区间」和 while 的终止条件,如果存在漏掉的元素,记得在最后检查。
3、如需定义左闭右开的「搜索区间」搜索左右边界,只要在 nums[mid] == target 时做修改即可,搜索右侧时需要减一。
4、如果将「搜索区间」全都统一成两端都闭,好记,只要稍改 nums[mid] == target 条件处的代码和返回的逻辑即可

代码

  1. class Solution {
  2. public int[] searchRange(int[] nums, int target) {
  3. return new int[]{leftBound(nums, target), rightBound(nums, target)};
  4. }
  5. public int leftBound(int[] nums, int target) {
  6. int left = 0, right = nums.length - 1;
  7. // 搜索区间为 [left, right]
  8. while (left <= right) {
  9. int mid = left + (right - left) / 2;
  10. if (nums[mid] < target) {
  11. // 搜索区间变为 [mid+1, right]
  12. left = mid + 1;
  13. } else if (nums[mid] > target) {
  14. // 搜索区间变为 [left, mid-1]
  15. right = mid - 1;
  16. } else if (nums[mid] == target) {
  17. // 收缩右侧边界
  18. right = mid - 1;
  19. }
  20. }
  21. // 检查出界情况
  22. if (left >= nums.length || nums[left] != target) {
  23. return -1;
  24. }
  25. return left;
  26. }
  27. public int rightBound(int[] nums, int target) {
  28. int left = 0, right = nums.length - 1;
  29. while (left <= right) {
  30. int mid = left + (right - left) / 2;
  31. if (nums[mid] < target) {
  32. left = mid + 1;
  33. } else if (nums[mid] > target) {
  34. right = mid - 1;
  35. } else if (nums[mid] == target) {
  36. // 这里改成收缩左侧边界即可
  37. left = mid + 1;
  38. }
  39. }
  40. // 这里改为检查 right 越界的情况,见下图
  41. if (right < 0 || nums[right] != target) {
  42. return -1;
  43. }
  44. return right;
  45. }
  46. }