本文介绍关于JS 中常见3种类型的二分搜索算法,需要的朋友可以参考一下:
目录
1、基本二分搜索
const rl = require("readline").createInterface({ input: process.stdin })
var iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
void async function () {
let nums = (await readline()).split(' ').map(Number)
let target = Number(await readline())
console.log(binarySearch(nums, target))
}()
// 通过基本的二分搜索寻找一个数返回其下标
function binarySearch (nums, target) {
let left = 0
let right = nums.length - 1
while (left <= right) {
let mid = parseInt((left + right) / 2, 10)
if (nums[mid] === target) {
return mid
} else if (nums[mid] > target) {
// 在左侧
right = mid - 1
} else if (nums[mid] < target) {
// 在右侧
left = mid + 1
}
}
// target不存在
return -1
}
用例测试1:
1 2 3 4 5
4
3
用例测试2:
1 2 3 4 5
8
-1
2、寻找左侧边界的二分搜索
取[left, right)区间
该方法所取区间为左闭右开区间,其终止条件是left 等于 right。能够搜索左边界的原因是其在遇到nums[mid] == target时不会立即返回,而是缩小搜索区间的上界right,在区间[left, mid)中继续搜索,即不断向左收缩,以此达到锁定左侧边界的目的。如果target比所有数都大,此时返回的索引将会是nums.length则证明没找到,返回-1。如果找到的数比所有的都小,将会返回索引为0,此时需要进行判断索引为0时是否是target值。
const rl = require("readline").createInterface({ input: process.stdin })
var iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
void async function () {
let nums = (await readline()).split(' ').map(Number)
let target = Number(await readline())
console.log(leftBound(nums, target))
}()
// 寻找左侧边界的二分搜索[left, right)
function leftBound (nums, target) {
if (nums.length === 0) {
return -1
}
let left = 0
let right = nums.length
while (left < right) {
let mid = parseInt((left + right) / 2, 10)
if (nums[mid] === target) {
right = mid
} else if (nums[mid] < target) {
left = mid + 1
} else if (nums[mid] > target) {
right = mid
}
}
// 如果left为nums.length则证明没找到,返回-1
if (left === nums.length) {
return -1
}
// 判断索引为0时值是否为target
return nums[left] === target ? left : -1
}
用例测试:
1 2 2 2 3
2
1
取[left, right]区间
const rl = require("readline").createInterface({ input: process.stdin })
var iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
void async function () {
let nums = (await readline()).split(' ').map(Number)
let target = Number(await readline())
console.log(leftBound(nums, target))
}()
// 寻找左侧边界的二分搜索[left, right]
function leftBound(nums, target) {
let left = 0;
let right = nums.length - 1;
while (left <= right) {
const mid = parseInt((left + right) / 2, 10);
if (nums[mid] === target) {
right = mid - 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] < target) {
left = mid + 1;
}
}
if (left >= nums.length || nums[left] !== target) {
return -1;
}
return left;
}
用例测试:
1 2 2 2 3
2
1
3、寻找右侧边界的二分搜索
取[left, right)区间
const rl = require("readline").createInterface({ input: process.stdin })
var iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
void async function () {
let nums = (await readline()).split(' ').map(Number)
let target = Number(await readline())
console.log(rightBound(nums, target))
}()
function rightBound(nums, target) {
if (nums.length === 0) {
return -1;
}
let left = 0;
let right = nums.length;
while (left < right) {
const mid = parseInt((left + right) / 2, 10);
if (nums[mid] === target) {
left = mid + 1;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid;
}
}
return left - 1;
}
用例测试:
1 2 2 2 3
2
1
取[left, right]区间
const rl = require("readline").createInterface({ input: process.stdin })
var iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
void async function () {
let nums = (await readline()).split(' ').map(Number)
let target = Number(await readline())
console.log(rightBound(nums, target))
}()
function rightBound(nums, target) {
let left = 0;
right = nums.length - 1;
while (left <= right) {
const mid = parseInt((left + right) / 2, 10);
if (nums[mid] === target) {
left = mid + 1;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
}
}
if (right < 0 || nums[right] !== target) {
return -1;
}
return right;
}
用例测试:
1 2 2 2 3
2
1
总结
到此关于JavaScript中3种常见类型二分搜索算法的介绍就结束了,更多关于JS算法刷题常用知识点后续还会更新,在阅读过程中如若有误,劳请指正;如若有妙解、疑惑也欢迎大家和我交流,感谢!