二分查找變種:
1. 查找大於target的所有值的最小索引;
2. 查找等於target的所有值的最大索引(上界);
3. 查找大於target的所有值的最大索引;
代碼示例:
/**
* 二分查找工具對象
*/
const BinarySearch = (function() {
return {
/**
* 找出大於target的所有值中的最小索引
* @param {number[]} nums - 有序數組
* @param {number} target - 目標值
*/
upper(nums, target) {
let l = 0;
let r = nums.length;
// 在[l, r) 範圍內查找target
while (l < r) {
// 中位數索引
const m = l + Math.floor((r - l) / 2);
// 如果m位置上的值比target小或者相等,則將左指針l移動至m + 1
if (nums[m] <= target) {
l = m + 1;
}
// 如果當前位置上的值比target大,則移動r至m
else {
r = m;
}
}
return l;
},
/**
* 找出等於target的值的最大索引(如果沒有等於target的值,則返回大於target的值中的最小索引)
* @param {number[]} nums - 有序數組
* @param {number} target - 目標值
*/
ceil(nums, target) {
// 先找出大於target元素的最小值的索引
const upper_idx = this.upper(nums, target);
// 如果該索引的前一個位置上的值正好等於target,返回該值
if (upper_idx > 0 && nums[upper_idx - 1] === target) {
return upper_idx - 1;
}
// 否則返回比大於target的值中的最小索引
return upper_idx;
},
/**
* 找出小於target的所有值中的最小索引
* @param nums
* @param target
*/
lower(nums, target) {
let l = 0;
let r = nums.length - 1;
// 在[l, r)範圍內搜索
while (l < r) {
// 相對於upper函數,這裏m的取值調整爲“上取整”(避免l留在原地,造成死循環 )
const m = l + Math.ceil((r - l) / 2);
// 當前值小於target,可能符合調整,所以將l指針調整m
if (nums[m] < target) {
l = m;
}
// 如果大於等於target(不合符搜索目標),將r調整到m - 1
else {
r = m - 1;
}
}
return l;
},
};
})();