题目
🔗题目链接:34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:你可以设计并实现时间复杂度为 的算法解决此问题吗?
示例 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]
思路
寻找 target 在数组中的左右边界,有如下三种情况:
- target 在数组的左边或右边。例如 nums = [3, 4, 5],target = 2。此时应该返回 [-1, -1]。
- target 在数组范围内,但数组中不存在 target。例如 nums = [3, 6, 7],target = 5。此时应该返回 [-1, -1]。
- target 在数组范围内,且数组中存在 target。例如 nums = [3, 6, 7],target = 6。此时应该返回[1, 1]。
代码
寻找右边界
// 寻找右边界,就是让 left 往右走
function getRightBorder(nums: number[], target: number): number {
const lens = nums.length;
// 定义 target 在左闭右闭的区间内 [left, right]
let left = 0;
let right = lens - 1;
let rightBorder = -2;
while (left <= right) {
let mid = Math.floor(left + (right - left) / 2);
if (target < nums[mid]) {
// target 在左边
// 如果 target 在数组的左边,只会更新 right,不会更新 left 和 rightBorder。这个函数返回的时候 rightBorder 仍为 -2。
right = mid - 1;
} else if (target > nums[mid]) {
// 为什么在这里也要更新 rightBorder
// 因为数组中可能不存在与 target 相等的值
left = mid + 1;
rightBorder = left;
} else {
// 当 nums[mid] = target 的时候,让 left 继续走,这样可以得到 target 的右边界
left = mid + 1;
rightBorder = left;
}
}
return rightBorder;
}
寻找左边界
// 寻找左边界,就是让 left 往左走
function getLeftBorder(nums: number[], target: number): number {
const lens = nums.length;
// 定义 target 在左闭右闭的区间内 [left, right]
let left = 0;
let right = lens - 1;
let leftBorder = -2;
while (left <= right) {
let mid = Math.floor(left + (right - left) / 2);
if (target < nums[mid]) {
// 为什么在这里也要更新 leftBorder
// 因为数组中可能不存在与 target 相等的值
right = mid - 1;
leftBorder = right;
} else if (target > nums[mid]) {
left = mid + 1;
} else {
// 当 nums[mid] = target 的时候,让 right 继续走,这样可以得到 target 的左边界
right = mid - 1;
leftBorder = right;
}
}
return leftBorder;
}
完整代码(需要加上寻找左右边界的代码)
function searchRange(nums: number[], target: number): number[] {
const leftBorder = getLeftBorder(nums, target);
const rightBorder = getRightBorder(nums, target);
// 情况一
// 如果左边界或者右边界未被赋值(-2),表示目标值不在数组中,在数组的左边或者右边
// 返回 [-1, -1]
if (-2 === leftBorder || -2 === rightBorder) return [-1, -1];
// 情况三
// 如果左右边界之间存在超过一个元素,则返回目标值的起始位置和结束位置
if (rightBorder - leftBorder > 1) return [leftBorder + 1, rightBorder - 1];
// 情况二
// 如果左右边界相邻或者相等,表示 target 的大小在数组范围内,但数组中没有与 target 相等的值
// 返回 [-1, -1]
return [-1, -1];
};