算法题:二分查找

要点

  • 递归 - 代码逻辑更加清晰
  • 非递归 - 性能更好
  • 时间复杂度O(logn) ——非常快
/**
 * @description 二分查找
 * @author lsr
 */

/**
 * 二分查找 - 循环
 * @param arr arr
 * @param target 目标值
 * @returns 目标值索引
 */
export function binarySearch1(arr: number[], target: number): number {
  const length = arr.length
  if (length === 0) return -1

  let startIndex = 0
  let endIndex = arr.length - 1

  while (startIndex <= endIndex) {
    const midIndex = Math.floor((startIndex + endIndex) / 2)
    const midValue = arr[midIndex]
    if (midValue > target) {
      // 中间值大于目标值,则证明目标值在左边
      endIndex = midIndex - 1
    } else if (midValue < target) {
      // 中间值小于目标值,则证明目标值在右边
      startIndex = midIndex + 1
    } else {
      // 找到目标值
      return midIndex
    }
  }

  return -1
}

/**
 * 二分查找 - 递归
 * @param arr arr
 * @param target 目标值
 * @param startIndex 开始索引
 * @param endIndex 结束索引
 * @returns 目标值索引
 */
export function binarySearch2(
  arr: number[],
  target: number,
  startIndex?: number,
  endIndex?: number
): number {
  const length = arr.length
  if (length === 0) return -1

  startIndex = startIndex || 0
  endIndex = endIndex || arr.length - 1

  if (startIndex > endIndex) return -1

  const midIndex = Math.floor((startIndex + endIndex) / 2)
  const midValue = arr[midIndex]
  if (midValue > target) {
    // 中间值大于目标值,则证明目标值在左边
    return binarySearch2(arr, target, startIndex, midIndex - 1)
  } else if (midValue < target) {
    // 中间值小于目标值,则证明目标值在右边
    return binarySearch2(arr, target, midIndex + 1, endIndex)
  } else {
    // 找到目标值
    return midIndex
  }
}

// 功能测试
// const arr = [10, 20, 30, 40, 50]
// const index = binarySearch1(arr, 30)
// console.log(index)

const arr = [10, 20, 30, 40, 50, 56, 67, 89, 90, 100, 134, 140, 150]
const target = 60
// const index = binarySearch2(arr, 31)
// console.log(index)

// 性能测试
console.time('binarySearch1')
for (let i = 0; i < 100 * 10000; i++) {
  binarySearch1(arr, target)
}
console.timeEnd('binarySearch1') // 16.400634765625 ms

console.time('binarySearch2')
for (let i = 0; i < 100 * 10000; i++) {
  binarySearch2(arr, target)
}
console.timeEnd('binarySearch2') // 36.666748046875 ms

单元测试

/**
 * @description 二分查找 test
 * @author lsr
 */

import { binarySearch1, binarySearch2 } from '@/01-algorithm/binary-search'

describe('二分查找 - 循环', () => {
  it('空数组', () => {
    const targetIndex = binarySearch1([], 100)
    expect(targetIndex).toBe(-1)
  })
  it('目标值不存在', () => {
    const arr = [10]
    const targetIndex = binarySearch1(arr, 100)
    expect(targetIndex).toBe(-1)
  })
  it('目标值存在', () => {
    const arr = [10, 20, 30, 40, 50]
    const targetIndex = binarySearch1(arr, 50)
    expect(targetIndex).toBe(4)
  })
})

describe('二分查找 - 递归', () => {
  it('空数组', () => {
    const targetIndex = binarySearch2([], 100)
    expect(targetIndex).toBe(-1)
  })
  it('目标值不存在', () => {
    const arr = [10]
    const targetIndex = binarySearch2(arr, 100)
    expect(targetIndex).toBe(-1)
  })
  it('目标值存在', () => {
    const arr = [10, 20, 30, 40, 50]
    const targetIndex = binarySearch2(arr, 50)
    expect(targetIndex).toBe(4)
  })
})

划重点

  • 凡有序,必二分
  • 凡二分,时间复杂度必包含O(logn)
  • 递归 vs 非递归(非递归更快,递归逻辑更清晰,较真级别的对比)

相关算法题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值