第一部分:题目描述
🏠 链接:34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
⭐ 难度:中等
第二部分:思路分析
需要使用 最靠左索引 与 最靠右索引 解决该问题。
- 最靠左索引:搜索目标值为 target 且 索引最小的索引位置
- 最靠右索引:搜索目标值为 target 且 索引最大的索引位置
📝 以 最靠左索引 为例来说明:
-
我们知道普通的二分查找是找到一个 目标值 就停止搜索,返回 中间索引 就可以了。
-
但这里我们需要查找 索引最小的索引位置,那么即使查找到了一个目标值不能直接返回,应该记录下当前的目标值对应的索引,即中间索引mid。
-
同时,查找到了这个目标值,我们应该缩小搜索的右边范围,既查找 当前mid索引 左边的范围。
-
即 需要设置
right = mid - 1
。
同理,最靠右索引也需要记录 每次查找到的索引,同时缩小搜索的左边范围,即设置 left = mid + 1
。
第三部分:代码实现
class Solution {
public int[] searchRange(int[] nums, int target) {
// 查找最小索引
int minIndex = searchMinIndex(nums, target);
// 如果未搜索到说明数组不存在目标值
if (minIndex == -1) {
return new int[]{-1, -1};
}
// 查找最大索引
int maxIndex = searchMaxIndex(nums, target);
return new int[]{minIndex, maxIndex};
}
private int searchMinIndex(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
// 记录最小索引
int minIndex = -1;
int mid;
while (left <= right) {
// 无符号右移 代替 /2 操作,避免 left + right 的超出 int能取的最大值
mid = (left + right) >>> 1;
if (target < nums[mid]) {
// 如果 目标值 小于 中间值
right = mid - 1;
} else if (nums[mid] < target) {
// 如果 目标值 大于 中间值
left = mid + 1;
} else {
// 记录当前中间索引为最小索引
minIndex = mid;
// 缩小右范围,以便能向左查找更小的索引
right = mid - 1;
}
}
return minIndex;
}
private int searchMaxIndex(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
// 记录最大索引
int maxIndex = -1;
int mid;
while (left <= right) {
// 无符号右移 代替 /2 操作,避免 left + right 的超出 int能取的最大值
mid = (left + right) >>> 1;
if (target < nums[mid]) {
// 如果 目标值 小于 中间值
right = mid - 1;
} else if (nums[mid] < target) {
// 如果 目标值 大于 中间值
left = mid + 1;
} else {
// 记录当前中间索引为最大索引
maxIndex = mid;
// 缩小左范围,以便能向右查找更大的索引
left = mid + 1;
}
}
return maxIndex;
}
}
public int[] searchRange(int[] nums, int target) {
// 查找最小索引
int minIndex = searchMinIndex(nums, target);
// 如果未搜索到说明数组不存在目标值
if (minIndex == -1) {
return new int[]{-1, -1};
}
// 查找最大索引
int maxIndex = searchMaxIndex(nums, target);
return new int[]{minIndex, maxIndex};
}
private int searchMinIndex(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
// 记录最小索引
int minIndex = -1;
int mid;
while (left <= right) {
// 无符号右移 代替 /2 操作,避免 left + right 的超出 int能取的最大值
mid = (left + right) >>> 1;
if (target < nums[mid]) {
// 如果 目标值 小于 中间值
right = mid - 1;
} else if (nums[mid] < target) {
// 如果 目标值 大于 中间值
left = mid + 1;
} else {
// 记录当前中间索引为最小索引
minIndex = mid;
// 缩小右范围,以便能向左查找更小的索引
right = mid - 1;
}
}
return minIndex;
}
private int searchMaxIndex(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
// 记录最大索引
int maxIndex = -1;
int mid;
while (left <= right) {
// 无符号右移 代替 /2 操作,避免 left + right 的超出 int能取的最大值
mid = (left + right) >>> 1;
if (target < nums[mid]) {
// 如果 目标值 小于 中间值
right = mid - 1;
} else if (nums[mid] < target) {
// 如果 目标值 大于 中间值
left = mid + 1;
} else {
// 记录当前中间索引为最大索引
maxIndex = mid;
// 缩小左范围,以便能向右查找更大的索引
left = mid + 1;
}
}
return maxIndex;
}