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

【JavaScript】JS二分搜索算法:基本二分搜索、寻找左侧边界的二分搜索、寻找右侧边界的二分搜索_第1张图片
本文介绍关于JS 中常见3种类型的二分搜索算法,需要的朋友可以参考一下:

目录

  • 1、基本二分搜索
  • 2、寻找左侧边界的二分搜索
    • 取[left, right)区间
    • 取[left, right]区间
  • 3、寻找右侧边界的二分搜索
    • 取[left, right)区间
    • 取[left, right]区间
  • 总结

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算法刷题常用知识点后续还会更新,在阅读过程中如若有误,劳请指正;如若有妙解、疑惑也欢迎大家和我交流,感谢!

你可能感兴趣的:(javascript,前端,开发语言,算法)