给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

102 阅读2分钟

给定一个按照升序排列的整数数组 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];
}