01--二分查找

一. 初识算法

1.1 什么是算法?

在数学和计算机科学领域,算法是一系列有限的严谨指令,通常用于解决一类特定问题或执行计算

不正式的说,算法就是任何定义优良的计算过程:接收一些值作为输入,在有限的时间内,产生一些值作为输出。

1.2 什么是数据结构?

在计算机科学领域,数据结构是一种数据组织、管理和存储格式,通常被选择用来高效访问数据

数据结构是一种存储和组织数据的方式,旨在便于访问和修改

1.3 衡量算法好坏

一般从以下维度来评估算法的优劣:正确性、可读性、健壮性 (对不合理输入的反应能力和处理能力)。
时间复杂度 (time complexity):估算程序指令的执行次数(执行时间)。
空间复杂度(space complexity):估算所需占用的存储空间。

1.3.1 时间复杂度

常见的时间复杂度从快到慢:

常数复杂度 O(1)

对数复杂度 O(logn)

线性时间复杂度 O(n)

线性对数复杂度 O(nlogn)

平方 O()

立方 O()

指数 O()

阶乘 O(n!)

1.3.2 空间复杂度

空间复杂度就是算法需要多少内存,占用了多少空间

常用的空间复杂度有O(1)、O(n)、O()

二、二分查找

二分查找算法也称折半查找,是一种非常高效的工作于有序数组的查找算法。

2.1 二分查找基础版

java 复制代码
	/**
     * @description: 二分查找基础版
     * @author: 憨憨浩浩
     * @date: 2023/12/11 21:54
     * @param: [a, target]
     * @return: int
     **/
    public static int binarySearchBasic(int[] a, int target) {
        // 定义左侧指针
        int i = 0;
        // 定义右侧指针
        int j = a.length - 1;
        // 当 i > j 时退出循环
        while (i <= j){
            // 定义中间指针
            int m = (i + j) / 2;
            if (a[m] > target){     // 目标值在左边
                j = m - 1;
            }else if (a[m] < target){       // 目标值在右边
                i = m + 1;
            }else {     // 找到目标值返回对应索引
                return m;
            }
        }
        return -1;      // 找不到目标值返回-1
    }

(i + j) / 2 有没有问题?

有问题,当数组长度足够长是会发生问题;

java 复制代码
	@Test
    public void Test01(){
        int i = Integer.MAX_VALUE / 2;
        int j = Integer.MAX_VALUE;
        int m = (i + j) / 2;
        System.out.println(m);		// -536870913
    }

解决方案:

java 复制代码
	@Test
    public void Test02(){
        int i = Integer.MAX_VALUE / 2;
        int j = Integer.MAX_VALUE;
        int m = (i + j) >>> 2;
        System.out.println(m);		// 805306367
    }

2.2 二分查找改变版

另一种写法

java 复制代码
	/**
     * @description: 二分查找改变版
     * @author: 憨憨浩浩
     * @date: 2023/12/11 22:10
     * @param: [a, target]
     * @return: int
     **/
    public static int binarySearchAlternative(int[] a,int target){
        // 定义左侧指针
        int i = 0;
        // 定义右侧指针
        int j = a.length;
        // 当 i = j 时退出循环
        while (i < j){
            // 定义中间指针
            int m = (i + j) /2;
            if (a[m] > target){     // 目标值在左边
                j = m;
            } else if (a[m] < target) {     // 目标值在右边
                i = m + 1;
            }else {     // 找到目标值返回对应索引
                return m;
            }
        }
        return -1;      // 找不到目标值返回-1
    }

2.3 二分查找性能

2.4 二分查找平衡版

java 复制代码
	/**
     * @description: 二分查找平衡版
     * @author: 憨憨浩浩
     * @date: 2023/12/13 13:46
     * @param: [a, target]
     * @return: int
     **/
    public static int binarySearchBalance(int[] a,int target){
        // 定义左侧指针
        int i = 0;
        // 定义右侧指针
        int j = a.length;
        // 当 i + 1 > j 时退出循环
        while (1 < j - i) {
            // 定义中间指针
            int m = (i + j) >>> 1;
            if (target < a[m]) {     // 目标值在左边
                j = m;
            } else {
                i = m;
            }
        }
        // 查到返回i,查不到返回-1
        return (a[i] == target) ? i : -1;
    }

2.5 二分查找 Java 版

Java8源码:

java 复制代码
public static int binarySearch(int[] a, int key) {
        return binarySearch0(a, 0, a.length, key);
    }


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

        while (low <= high) {
            int mid = (low + high) >>> 1;
            int 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.
    }

2.6 Leftmost 与 Rightmost

java 复制代码
	/**
     * @description: 二分查找返回左侧的索引值
     * @author: 憨憨浩浩
     * @date: 2023/12/15 20:21
     * @param: [a, target]
     * @return: int
     **/
    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;
    }

如果希望返回的是最右侧元素

java 复制代码
	/**
     * @description: 二分查找返回最右侧值的索引
     * @author: 憨憨浩浩
     * @date: 2023/12/15 20:23
     * @param: [a, target]
     * @return: int
     **/
    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;
    }

应用

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

Leftmost 改为

java 复制代码
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; 
}

Rightmost 改为

java 复制代码
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;
}

大于等于中间值,都要向右找

几个名词

相关推荐
在努力的前端小白2 小时前
Spring Boot 敏感词过滤组件实现:基于DFA算法的高效敏感词检测与替换
java·数据库·spring boot·文本处理·敏感词过滤·dfa算法·组件开发
麦兜*3 小时前
Swift + Xcode 开发环境搭建终极指南
开发语言·ios·swiftui·xcode·swift·苹果vision pro·swift5.6.3
Coovally AI模型快速验证4 小时前
农田扫描提速37%!基于检测置信度的无人机“智能抽查”路径规划,Coovally一键加速模型落地
深度学习·算法·yolo·计算机视觉·transformer·无人机
pusue_the_sun4 小时前
数据结构:二叉树oj练习
c语言·数据结构·算法·二叉树
萧鼎4 小时前
Python pyzmq 库详解:从入门到高性能分布式通信
开发语言·分布式·python
一叶飘零_sweeeet4 小时前
从繁琐到优雅:Java Lambda 表达式全解析与实战指南
java·lambda·java8
RaymondZhao344 小时前
【全面推导】策略梯度算法:公式、偏差方差与进化
人工智能·深度学习·算法·机器学习·chatgpt
艾伦~耶格尔5 小时前
【集合框架LinkedList底层添加元素机制】
java·开发语言·学习·面试
zhangfeng11335 小时前
DBSCAN算法详解和参数优化,基于密度的空间聚类算法,特别擅长处理不规则形状的聚类和噪声数据
算法·机器学习·聚类
yujkss5 小时前
Python脚本每天爬取微博热搜-终版
开发语言·python