给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
题目描述:
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
*
* 如果数组中不存在目标值 target,返回 [-1, -1]。
*
* 进阶:你可以设计并实现时间复杂度为 $O(\log n)$ 的算法解决此问题吗?
*
* 示例 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]
思路:
1.target在左边或者左边
2.target中间
3.不在目标数组内
有符号右移操作符(>>)会将数值的32位全部右移若干位(同时会保留正负号)。正数左补0,负数左补1,右边丢弃。操作数每右移一位,相当于该数除以2。
const searchRange = function (nums, target) {
//查找第一个大于target元素的下表 - 1就是边界
const getRightBorder = function (nums, target) {
let rightBorder = -2;
let left = 0
let right = nums.length - 1;//定义target在左闭右闭的去建立
//left === right时候,[left,right] 区间依然有效
while (left <= right) {
//防止大数溢出
const mid = left + ((right - left) >> 1);
//Math.floor浮点数向下取整
if (nums[mid] > target) {
//[left,nums[mid - 1]] 目标在左区间
//收缩右边界
right = mid - 1;
} else {
//右边界一定在mid的右边(不含mid)
left = mid + 1;
rightBorder = left
}
// } else if (nums[mid] === target) {
// // 因为是要寻找右边界,需要收缩左边
// //收缩左边界
// left = mid + 1
// } else {
// //右边界一定在mid的右边(不含mid)
// left = mid + 1;
// rightBorder = left
// }
}
return rightBorder;
}
//查找第一个小于target元的下标 + 1就是左边界
const getLeftBorder = function (nums, target) {
let leftBorder = -2;
let left = 0
let right = nums.length - 1; //表示nums区间的右边界
//左边界小于右边界
while (left <= right) {
//取中间值
const mid = left + ((right - left) >> 1);
if (nums[mid] >= target) { //寻找左边界,就要在nums[mid】 === target 的时候更新right
right = mid - 1;
leftBorder = right
} else {
left = mid + 1
}
}
return left;
}
let rightBorder = getRightBorder(nums, target)
let leftBorder = getLeftBorder(nums, target)
// 情况一:target 在数组范围的右边或者左边,例如数组{3, 4, 5},target为2或者数组{3, 4, 5},target为6,此时应该返回{-1, -1}
if (leftBorder === -2 || rightBorder === -2) return [-1, -1]
// 情况三:target 在数组范围中,且数组中存在target,例如数组{3,6,7},target为6,此时应该返回{1, 1}
if (rightBorder - leftBorder > 1) {
return [leftBorder + 1, rightBorder - 1]
}
// 情况二:target 在数组范围中,且数组中不存在target,例如数组{3,6,7},target为5,此时应该返回{-1, -1}
return [-1, -1];
}