【leetcode】2089. 找出数组排序后的目标下标

84 阅读1分钟

leetcode-2089.png

对于二分查找来说,并非简单的查找到目标元素即可,例如这一题,要求查找到排序后的第一个以及最后一个元素的索引。
下面分别用了两个函数来实现,其中细节不同在于while内的if判断,这里的判断根据条件不同,有着不同的判定。
例如,查找第一个满足条件的元素索引,那么我们肯定要一直将右边界向左边界逼近,这样才能查找到第一个符合条件的索引。所以在if判断的时候,相等的情况就需要来收缩右边界(也就是else里面的情况)。反之在第二个函数findLast中亦然。

最后需要注意的是,findLast里面返回的left是第一个大于target的位置

var targetIndices = function (nums, target) {
    nums.sort((a, b) => a - b)
    let first = findFirst(nums, target)
    let last = findLast(nums, target)
    let res = []
    if (first !== -1 && last !== -1) {
        for (let i = first; i <= last; ++i) {
            res.push(i)
        }
    }
    return res
};

var findFirst = function (nums, target) {
    let left = 0, right = nums.length
    while (left < right) {
        let mid = Math.floor((left + right) / 2)
        // first
        if (target > nums[mid]) {
            left = mid + 1
        } else {
            // 相等的情况,收缩右边界,逼近左边
            right = mid
        }
    }
    //如果 `target` 存在于数组中,`left` 会指向数组中第一个等于 `target` 的位置。
    //如果 `target` 不存在于数组中,`left` 会指向第一个大于 `target` 的元素的索引。
    return (left < nums.length && nums[left] === target) ? left : -1
}

var findLast = function (nums, target) {
    let left = 0, right = nums.length
    while (left < right) {
        let mid = Math.floor((left + right) / 2)
        // last
        if (target < nums[mid]) {
            right = mid
        } else {
            // 相等的情况,收缩左边界,逼近右边
            left = mid + 1
        }
    }
    // 由于 left 是第一个大于 target 的位置,因此需要返回 left - 1 作为最后一个满足条件的索引
    return (left - 1 >= 0 && nums[left - 1] === target) ? left - 1 : -1
}