34. 在排序数组中查找元素的第一个和最后一个位置
这题本质上是用两次二分查找第一次找target的最左位置第二次找target的最右位置因为数组有序所以可以O(log n)。一、核心思想比如nums [5,7,7,8,8,10] target 8我们想得到[3,4]也就是第一个 8 在哪里最后一个 8 在哪里二、为什么普通二分不够普通二分只能找到“某一个” 8但题目要的是第一个8 和 最后一个8所以要“偏向左找”和“偏向右找”。三、找左边界思想即使找到 targetnums[mid] target也不能立刻返回。因为左边可能还有 target。所以right mid - 1继续向左压缩。过程示例nums [5,7,7,8,8,10] target 8初始left 0 right 5第一次mid 2 nums[2] 77 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也不停止继续压右边这就是这题的本质。