算法随笔 — 搜索查找算法 — 二分查找

本文详细介绍了二分查找的基本原理和应用场景,包括查找目标值、寻找平方根、搜索插入位置、两数之和等问题。文章通过分析LeetCode上的经典题目,展示了二分查找在有序序列中的应用,同时探讨了在不同情况下如何调整中间指针的偏向。此外,还讨论了二分查找在搜索旋转排序数组、供暖器问题和寻找两个正序数组中位数等问题中的解决方案,强调了理解01模型的重要性。
摘要由CSDN通过智能技术生成

二分查找原理

二分查找是应用于 顺序 序列的一种算法,在查找的过程中我们在 保证目标值在查找范围 的前提下不断 缩小 查找范围,最终找到目标值

首先介绍最朴素的二分查找算法,这个算法用于定位给定的目标值,如果找不到则返回 -1

首先要设定头尾两个指针,然后通过中间值 (head + tail) >> 1 进行比较,如果中间值和目标值相等则直接返回目标值,否则进行如下操作

{ a r r [ m i d ] < x , h e a d = m i d + 1 a r r [ m i d ] > x , t a i l = m i d − 1 \begin{cases} arr[mid]<x,head=mid+1 \\ arr[mid] > x,tail = mid - 1 \end{cases} { arr[mid]<xhead=mid+1arr[mid]>xtail=mid1

这里的操作很容易想明白,目标是为了保证目标在查找范围内缩小查找范围

二分查找缩小范围

function binarySearch (nums: number[], target: number) {
   
    let h = 0, t = nums.length - 1, mid: number
    while (h <= t) {
   
        mid = (t + h) >> 1
        if (nums[mid] === target) return mid
        if (nums[mid] < target) h = mid + 1
        else t = mid - 1
    }
    return -1
}

01模型

00001111

这个模型通常用来找 最后一个0第一个1

这里的 最后一个0 可以理解为 最后一个小于等于x 的值;
第一个1 可以理解为 第一个大于等于x 的值。

这里以 查找第一个大于等于x的值为例 进行推理

// 01-1 核心部分
while (h < t) {
   
	// 中间指针
    mid = (h + t) >> 1
    // 范围缩小选择
    if (nums[mid] <= target) h = mid
    else t = mid - 1
}

01-1

// 01-1 核心代码
function b_binarySearch (nums: number[], target: number) {
   
    let h = 0, t = nums.length - 1, mid: number
    while (h < t) {
   
        mid = (h + t) >> 1
        // mid = h + ((t - h) >> 1)
        if (nums[mid] >= target) t = mid
        else h = mid + 1
    }
    return h
}

同理得出 01-0 代码

// 01-0 核心代码
function s_binarySearch (nums: number[], target: number) {
   
    let h = 0, t = nums.length - 1, mid: number
    while (h < t) {
   
        mid = h + ((t - h) >> 1) + 1  // 无论什么情况都往右偏一位
        // parseInt(`${(h + t + 1) / 2}`) // 奇数时找到中间值,偶数时找到中间偏右
        if (nums[mid] <= target) h = mid
        else t = mid - 1
    }
    return h
}

中间指针的偏向

在上面的代码中可以发现 01-001-1mid 有细微的差别

在搜索序列中如果元素个数是奇数的话,二者定位到的中间值是一样的;但如果是偶数, 01-0 定位到的是中间偏右的值,而 01-1 定位到的是中间偏左的值

如果是右偏的话,有两种情况

  1. 如上所述,奇数时定位到正中间,偶数时定位到中间偏右的数字
    mid = parseInt(`${
           (h + t + 1) / 2}`)
    
  2. 指针均向右偏一位
    mid = ((h + t) >> 1) + 1
    mid = h + ((t - h) >> 1) + 1 // 在静态语言中,这种写法可以防止溢出
    

这两种情况都是行得通的

指针偏向原理


二分查找题目

leetCode 69 x的平方根

leetCode69题目
这道题可以转化为 查找最后一个小于等于x的值

function mySqrt(x: number): number {
   
    let h = 0, t = x, mid: number
    while (h < t) {
   
        mid = ((h 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值