算法笔记(二):二分查找

news2024/9/28 19:24:28

二分查找

1、基础版

public static int binarySearch(int[] a, int target) {
    int i = 0, j = a.length - 1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {			// 在左边
            j = m - 1;
        } else if (a[m] < target) {		// 在右边
            i = m + 1;
        } else {
            return m;
        }
    }
    return -1;
}

i 是插入点

2、左闭右开区间

核心:j索引位置的元素,一定不是要查找的元素

public static int binarySearch(int[] a, int target) {
    int i = 0, j = a.length;
    while (i < j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {			// 在左边
            j = m;
        } else if (a[m] < target) {		// 在右边
            i = m + 1;
        } else {
            return m;
        }
    }
    return -1;
}

3、平衡版

问题:当查找的元素在数组最左边或者最右边时,就会导致不平衡

public static int binarySearchBalance(int[] a, int target) {
    int i = 0, j = a.length;
    while (1 < j - i) {    //j-i是指还未被比较的元素个数,只有一个时,直接跳出循环
        int m = (i + j) >>> 1;
        if (target < a[m]) {
            j = m;
        } else {
            i = m;
        }
    }
    return (a[i] == target) ? i : -1;
}

优点:循环内比较次数少了
缺点:必须等退出循环了才能得到结果

注意:i不能等于m+1,因为else的情况包括target==a[m],如果i=m+1,那就略过了这个正确的查询结果

4、二分查找 Java 版

private static int binarySearch0(long[] a, int fromIndex, int toIndex,
                                     long key) {
    int low = fromIndex;
    int high = toIndex - 1;

    while (low <= high) {
        int mid = (low + high) >>> 1;
        long midVal = a[mid];

        if (midVal < key)
            low = mid + 1;
        else if (midVal > key)
            high = mid - 1;
        else
            return mid; // key found
    }
    return -(low + 1);  // key not found.
}
  • 例如 [ 1 , 3 , 5 , 6 ] [1,3,5,6] [1,3,5,6] 要插入 2 2 2 ,那么就是找到一个位置,这个位置左侧元素都比它小
    • 等循环结束,若没找到,low 左侧元素肯定都比 target 小,因此 low 即插入点
  • 插入点取负是为了与找到情况区分
  • -1 是为了把索引 0 位置的插入点与找到的情况进行区分

5、最左/最右

  • 对于数组 [ 1 , 2 , 3 , 4 , 4 , 5 , 6 , 7 ] [1, 2, 3, 4, 4, 5, 6, 7] [1,2,3,4,4,5,6,7],查找元素4,结果是索引3

  • 对于数组 [ 1 , 2 , 4 , 4 , 4 , 5 , 6 , 7 ] [1, 2, 4, 4, 4, 5, 6, 7] [1,2,4,4,4,5,6,7],查找元素4,结果也是索引3,并不是最左侧的元素

如果希望返回的是要查找的元素中最左侧元素

public static int binarySearchLeftmost1(int[] a, int target) {
    int i = 0, j = a.length - 1;
    int candidate = -1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {
            j = m - 1;
        } else if (a[m] < target) {
            i = m + 1;
        } else {
            candidate = m; // 记录候选位置
            j = m - 1;     // 继续向左
        }
    }
    return candidate;
}

如果希望返回的是要查找的元素中最右侧元素

public static int binarySearchRightmost1(int[] a, int target) {
    int i = 0, j = a.length - 1;
    int candidate = -1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {
            j = m - 1;
        } else if (a[m] < target) {
            i = m + 1;
        } else {
            candidate = m; // 记录候选位置
            i = m + 1;	   // 继续向右
        }
    }
    return candidate;
}

6、最左/最右升级版

对于 Leftmost 与 Rightmost,可以返回一个比 -1 更有用的值

Leftmost 改为

public static int binarySearchLeftmost(int[] a, int target) {
    int i = 0, j = a.length - 1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target <= a[m]) {
            j = m - 1;
        } else {
            i = m + 1;
        }
    }
    return i; 
}
  • leftmost 返回值的另一层含义: < t a r g e t \lt target <target 的元素个数
  • 小于等于中间值,都要向左找

Rightmost 改为

public static int binarySearchRightmost(int[] a, int target) {
    int i = 0, j = a.length - 1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {
            j = m - 1;
        } else {
            i = m + 1;
        }
    }
    return i - 1;
}
  • 大于等于中间值,都要向右找

在这里插入图片描述

7、范围查询

  • 查询 x < 4 x \lt 4 x<4 0.. l e f t m o s t ( 4 ) − 1 0 .. leftmost(4) - 1 0..leftmost(4)1
  • 查询 x ≤ 4 x \leq 4 x4 0.. r i g h t m o s t ( 4 ) 0 .. rightmost(4) 0..rightmost(4)
  • 查询 4 < x 4 \lt x 4<x,$rightmost(4) + 1 … \infty $
  • 查询 4 ≤ x 4 \leq x 4x l e f t m o s t ( 4 ) . . ∞ leftmost(4) .. \infty leftmost(4)..∞
  • 查询 4 ≤ x ≤ 7 4 \leq x \leq 7 4x7 l e f t m o s t ( 4 ) . . r i g h t m o s t ( 7 ) leftmost(4) .. rightmost(7) leftmost(4)..rightmost(7)
  • 查询 4 < x < 7 4 \lt x \lt 7 4<x<7 r i g h t m o s t ( 4 ) + 1.. l e f t m o s t ( 7 ) − 1 rightmost(4)+1 .. leftmost(7)-1 rightmost(4)+1..leftmost(7)1

8、求排名

l e f t m o s t ( t a r g e t ) + 1 leftmost(target) + 1 leftmost(target)+1

  • t a r g e t target target 可以不存在,如: l e f t m o s t ( 5 ) + 1 = 6 leftmost(5)+1 = 6 leftmost(5)+1=6
  • t a r g e t target target 也可以存在,如: l e f t m o s t ( 4 ) + 1 = 3 leftmost(4)+1 = 3 leftmost(4)+1=3

9、求前任

l e f t m o s t ( t a r g e t ) − 1 leftmost(target) - 1 leftmost(target)1

  • l e f t m o s t ( 3 ) − 1 = 1 leftmost(3) - 1 = 1 leftmost(3)1=1,前任 a 1 = 2 a_1 = 2 a1=2
  • l e f t m o s t ( 4 ) − 1 = 1 leftmost(4) - 1 = 1 leftmost(4)1=1,前任 a 1 = 2 a_1 = 2 a1=2

10、求后任

r i g h t m o s t ( t a r g e t ) + 1 rightmost(target)+1 rightmost(target)+1

  • r i g h t m o s t ( 5 ) + 1 = 5 rightmost(5) + 1 = 5 rightmost(5)+1=5,后任 a 5 = 7 a_5 = 7 a5=7
  • r i g h t m o s t ( 4 ) + 1 = 5 rightmost(4) + 1 = 5 rightmost(4)+1=5,后任 a 5 = 7 a_5 = 7 a5=7

11、求最近邻居

  • 前任和后任距离更近者

12、二分查找性能(复杂度)

下面分析二分查找算法的性能

时间复杂度

  • 最坏情况: O ( log ⁡ n ) O(\log n) O(logn)
  • 最好情况:如果待查找元素恰好在数组中央,只需要循环一次 O ( 1 ) O(1) O(1)

空间复杂度

  • 需要常数个指针 i , j , m i,j,m i,j,m,因此额外占用的空间是 O ( 1 ) O(1) O(1)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/929113.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用正则处理Unicode 编码的文本

Unicode&#xff08;中文&#xff1a;万国码、国际码、统一码、单一码&#xff09;是计算机科学领域里的一项业界标准。它对世界上大部分的文字进行了整理、编码。Unicode 使计算机呈现和处理文字变得简单。 现在的 Unicode 字符分为 17 组编排&#xff0c;每组为一个平面&…

前端工程化之规范化

规范化是我们践行前端工程化中重要的一部分。 为什么要有规范化标准 俗话说&#xff0c;无规矩不成方圆&#xff0c;尤其是在开发行业中&#xff0c;更是要有严谨的工作态度&#xff0c;我们都知道大多数软件开发都不是一个人的工作&#xff0c;都是需要多人协同的&#xff0…

C++内存模型

目录 内存模型分类 堆和栈的区别 C中new的工作过程 堆和栈的区别 为什么堆区要比栈区大 内存模型分类 文本段&#xff08;ELF&#xff09;&#xff08;数据区&#xff09;&#xff1a;主要用于存放我们编写的代码&#xff0c;但是不是按照代码文本的形式存放&#xff0c;而…

MySQL的日志undolog、binlog、redolog

1. 日志层次 binlog是Server层&#xff0c;undolog和redolog是innodb引擎层特有的。 2. 记录了什么 & 作用 binlog 记录了所有数据库结构变更和表数据修改的SQL日志。 主要用于数据备份和主从复制&#xff0c;比如误删数据了可以用binlog找回。 undolog 如下图&#…

测试一下阿里通义千问-7B-Chat的性能

测试一下阿里通义千问-7B-Chat的性能 0. 背景1. 实际测试结果(截图) 0. 背景 为了了解一下阿里通义千问-7B-Chat的性能&#xff0c;出了几个问题测试一下。 1. 实际测试结果(截图) 示例代码&#xff0c; import os import openaifrom dotenv import load_dotenv, find_dote…

gma 2 教程(二)数据操作:6.NumPy数组交互

gma 栅格数据集可以通过 ToArray 方法将栅格数据转为NumPy数组&#xff0c;也提供将NumPy数据转换为栅格数据&#xff08;集&#xff09;的方法。 读取NumPy数组到数据集 &#xff08;一&#xff09;函数简介   &#xff08;二&#xff09;示例 保存NumPy数组到文件 &…

基于热交换算法优化的BP神经网络(预测应用) - 附代码

基于热交换算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于热交换算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.热交换优化BP神经网络2.1 BP神经网络参数设置2.2 热交换算法应用 4.测试结果&#xff1a;5.Matlab代…

leetcode496. 下一个更大元素 I 【单调栈】

【简单题】&#xff08;暴力遍历法很简单&#xff09;但是时间复杂度很高&#xff0c;n的立方级别了。。。 代码&#xff1a; class Solution { public:vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {vector<int&g…

Vue2向Vue3过度核心技术computed计算属性

目录 1 computed计算属性1.1 概念1.2 语法1.3 注意1.4.案例1.5.代码准备 2 computed计算属性 VS methods方法2.1 computed计算属性2.2 methods计算属性2.3 计算属性的优势2.4 总结 3 计算属性的完整写法 1 computed计算属性 1.1 概念 基于现有的数据&#xff0c;计算出来的新属…

抓包相关,抓包学习

检查网络流量 - 提琴手经典 (telerik.com) Headers Reference - Fiddler Classic (telerik.com) 以上是fiddler官方文档 F12要勾选保留日志 不勾选的话跳转到新页面之前页面的日志不会在下方显示 会保留所有抓到的包 如果重定向到别的页面 F12抓包可能看不到响应信息,但是…

在Jupyter Notebook中添加Anaconda环境(内核)

在使用前我们先要搞清楚一些事&#xff1a; 我们在安装anaconda的时候它就内置了Jupyter Notebook&#xff0c;这个jupyter初始只有base一个内核&#xff08;显示为Python3&#xff09; 此后其实我们就不需要重复安装完整的jupyter notebook了&#xff0c;只要按需为其添加新的…

Nexus 如何配置匿名用户访问一个仓库

现在有这样一个需求&#xff0c;我们需要匿名用户访问 Nexus 的一个公共仓库。 设置 Roles 在满足这个需求之前&#xff0c;我们需要设置一个 Roles。 Role 的名字是可以随填写的。 这里关键的问题在你需要访问的仓库的 View 的权限需要设置 Read 和 Browse 这 2 个权限。 如…

保姆级使用vmware安装Ubuntu-server版

保姆级VMware安装Ubuntu20服务器版 文章目录 保姆级VMware安装Ubuntu20服务器版前期准备一、安装vmware二、下载Ubuntu镜像 VMware安装Ubuntu201. 启动Workstation Pro或者Workstation Player,进入软件后新建一个虚拟机2. 进入引导界面选择默认的即可3. 点击下一步即可4. 选择操…

【HSPCIE仿真】HSPICE仿真基础

HSPICE概述 1. HSPICE简介3. 标准输入文件4. 标准输出文件3. HSPCIE仿真过程 1. HSPICE简介 SPICE &#xff08;Simulation Program with IC Emphasis&#xff09;是1972 年美国加利福尼亚大学柏克莱分校电机工程和计算机科学系开发 的用于集成电路性能分析的电路模拟程序。 …

4.1011

目录 四次挥手中收到乱序的FIN包会如何处理&#xff1f; 在 TIME_WAIT 状态的 TCP 连接&#xff0c;收到 SYN 后会发生什么&#xff1f; 四次挥手中收到乱序的FIN包会如何处理&#xff1f; 如果FIN报文比数据包先道道客户端&#xff0c;此时FIN是一个乱序报文&#xff0c;此时…

双向交错CCM图腾柱无桥单相PFC学习仿真与实现(3)硬件功能实现

前言 前面介绍了双向交错CCM图腾柱的系统设计仿真实现&#xff0c;仿真很理想 双向交错CCM图腾柱无桥单相PFC学习仿真与实现&#xff08;1&#xff09;系统问题分解_卡洛斯伊的博客-CSDN博客 然后又介绍了SOG锁相环仿真实现的原理 双向交错CCM图腾柱无桥单相PFC学习仿真与实…

Python项目开发案例————学生信息管理系统(附源码)

一、学生信息管理系统 本文使用Python语言开发了一个学生信息管理系统&#xff0c;该系统可以帮助教师快速录入学生的信息&#xff0c;并且对学生的信息进行基本的增、删、改、查操作&#xff1b;还可以实时地将学生的信息保存到磁盘文件中。 1.1 需求分析 为了顺应互联网时代…

ELK + Kibana + Logstash实现可视化日志

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;elasticsearch、kibana、logstash、日志收集、日志可视化☀️每日 一言&#xff1a;坚持就是胜利啊&#xff0c;哥~ 一、前言 面试官&#xff1a;在日常开发工作中你们是如何查看日志的呢&#x…

9.2 互补功率放大电路

目前使用最广泛的是无输出变压器的功率放大电路&#xff08;OTL 电路&#xff09;和无输出电容的功率放大电路&#xff08;OCL 电路&#xff09;。 一、OCL 电路的组成及工作原理 为了消除图9.1.5所示的基本 OCL 电路所产生的交越失真&#xff0c;应当设置合适的静态工作点&a…