对于二分查找来说,并非简单的查找到目标元素即可,例如这一题,要求查找到排序后的第一个以及最后一个元素的索引。
下面分别用了两个函数来实现,其中细节不同在于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
}