算法学习笔记——二分搜索

二分搜索

在有序数组中确定num存在还是不存在:

  • arr[m] == num,则num存在
  • arr[m] > num,则 r = m - 1,缩小r的范围,继续往左二分
  • arr[m] < num,则l = m + 1,缩小l的范围,继续往右二分
java 复制代码
// 保证arr有序,才能用这个方法
public static boolen exist(int[] arr, int num) {
    if (arr == null || arr.length == 0){
        return false;
    }
    int l = 0, r = arr.length - 1, m = 0;
    while (l <= r) {
        // 中间值
        m = l + ((r - l) >> 1);
        if (arr[m] == num) {
            // 中间值 == num,直接返回结果
            return true;
        } else if (arr[m] > num) {
            // 中间值 > num,缩小r的范围
            r = m - 1;
        } else {
            // 中间值 < num, 缩小l的范围
            l = m + 1;
        }
    }
    return false;
}

有序数组中找>=num的最左位置:

  • ans(二分搜索法答案) 初始值设置为:-1,-1表示不存在符合要求的值
  • middle(中点值) >= num 时修改ans = middle 并 r = middle - 1 缩小右边范围,继续往左二分
  • middle(中点值) < num 时 不修改 ans 但 l = middle + 1 缩小左边范围 ,继续往右二分
  • 求中间值公式用:l + ((r - l) >> 1) 或者 l + ((r - 1) / 2),防止运算数值溢出
  • 找<=num的最左位置没有意义,直接找下标为0的位置进行判断就可以得出结果
java 复制代码
// 保证arr有序,才能用这个方法
// 有序数组中找>=num的最左位置
public static int findLeft(int[] arr, int num) {
    int l = 0, r = arr.length - 1, m = 0;
    int ans = -1;
    while (l <= r){
        m = l + ((r - l) >> 1); // 等于 l + ((r - 1) / 2), 等于 (l + r) / 2
        if (arr[m] >= num) {
            ans = m;
            r = m - 1;
        } else {
            l = m + 1;
        }
    }
    return ans;
}

在有序数组中找<=num的最右位置:

  • ans(二分搜索法答案) 初始值设置为:-1,-1表示不存在符合要求的值
  • middle(中点值) <= num 时修改ans = middle 并 l = middle + 1 缩小右边范围,继续往右二分
  • middle(中点值) > num 时 不修改 ans 但 r = middle - 1 缩小左边范围 ,继续往左二分
  • 求中间值公式用:l + ((r - l) >> 1) 或者 l + ((r - 1) / 2),防止运算数值溢出
java 复制代码
// 保证arr有序,才能用这个方法
// 有序数组中找<=num的最右位置
public static int findLeft(int[] arr, int num) {
    int l = 0, r = arr.length - 1, m = 0;
    int ans = -1;
    while (l <= r){
        m = l + ((r - l) >> 1); // 等于 l + ((r - 1) / 2), 等于 (l + r) / 2
        if (arr[m] <= num) {
            ans = m;
            l = m + 1;
           
        } else {
           r = m - 1;
        }
    }
    return ans;
}

二分搜索不一定发生在有序数组上(比如寻找峰值问题):

  • 峰值:i-1 < i > i+1,则i为峰值,如果右边或者左边没数值可以认为是无穷小

  • 数组条件:数组中相邻的两个数不相等, 只返回一个峰值就行

  • 0位置不是峰值,N-1位置不是峰值,则呈现左边上扬右边下降的趋势,这中间会出现一个或者多个峰值

  • 计算步骤:

    1. 先判断数组[0]是不是峰值,是则直接返回
    2. 再判断数组[N-1]是不是峰值,是则直接返回
    3. 设置 L = 1,R = N-2,求中间值,如果中间值是峰值则直接返回
    4. 判断中间值的大小,当左侧数值>中间值,往左侧二分,而右侧数值>中间值,往右侧二分,如果两个都成立选其中一个就行
    java 复制代码
    // 峰值元素是指其严格大于左右相邻值的元素
    // 给你一个整数数组 nums,已知任何两个相邻的值都不相等
    // 找到峰值元素并返回其索引
    // 数组可能包含多个峰值,在这种情况下,返回任何一个峰值 所在位置即可
    // 你可以假设 nums[-1] = nums[n] = 无穷小
    // 你必须实现时间复杂度为 0(log n) 的算法来解决此问题
    public static int findPeakElement(int[] arr) {
        int n = arr.length;
        // 小   小
        // -1 0 1
        if (arr.length == 1) {
            return 0;
        }
        // 数组长度 >= 2
        // 单独验证0位置,是不是峰值点
        if (arr[0] > arr[1]) {
            return 0;
        }
        //  单独验证n-1位置,是不是峰值点
        if (arr[n - 1] > arr[n - 2]) {
            return n - 1;
        }
        // X   中间一定有一个峰值    X
        // 0                      N-1
        // 中间 :1 ~ n-2 ,一定有峰值点
        // 每一步的l...r : 一定有峰值点
        int l = 1, r = n - 2, m = 0, ans = -1;
        while (l <= r) {
            m = l + ((r - l) >> 1);
            if (arr[m - 1] > arr[m]) {
                r = m - 1;
            } else if (arr[m] < arr[m + 1]) {
                l = m + 1;
            } else {
                ans = m;
                break;
            }
        }
        return ans;
    }

某侧必有对应的值或者某侧必没有对应的值,则可以使用二分搜索法

如果数组长度为n,那么二分搜索搜索次数是log n次,以2为底

二分搜索世界复杂度o(log n)

相关推荐
scdifsn1 小时前
动手学深度学习12.7. 参数服务器-笔记&练习(PyTorch)
pytorch·笔记·深度学习·分布式计算·数据并行·参数服务器
恰薯条的屑海鸥2 小时前
零基础在实践中学习网络安全-皮卡丘靶场(第十六期-SSRF模块)
数据库·学习·安全·web安全·渗透测试·网络安全学习
int型码农2 小时前
数据结构第八章(一) 插入排序
c语言·数据结构·算法·排序算法·希尔排序
UFIT2 小时前
NoSQL之redis哨兵
java·前端·算法
喜欢吃燃面2 小时前
C++刷题:日期模拟(1)
c++·学习·算法
SHERlocked932 小时前
CPP 从 0 到 1 完成一个支持 future/promise 的 Windows 异步串口通信库
c++·算法·promise
怀旧,2 小时前
【数据结构】6. 时间与空间复杂度
java·数据结构·算法
积极向上的向日葵2 小时前
有效的括号题解
数据结构·算法·
GIS小天3 小时前
AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年6月7日第101弹
人工智能·算法·机器学习·彩票
_Itachi__3 小时前
LeetCode 热题 100 74. 搜索二维矩阵
算法·leetcode·矩阵