【JavaScript】JS二分搜索算法:基本二分搜索、寻找左侧边界的二分搜索、寻找右侧边界的二分搜索

图片来源网络,详细信息不详,仅供欣赏呦
本文介绍关于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算法刷题常用知识点后续还会更新,在阅读过程中如若有误,劳请指正;如若有妙解、疑惑也欢迎大家和我交流,感谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IceSugarJJ

谢谢你对我的肯定[乖巧]

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值