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

二分搜索

在有序数组中确定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)

相关推荐
88号技师1 小时前
2024年12月一区SCI-加权平均优化算法Weighted average algorithm-附Matlab免费代码
人工智能·算法·matlab·优化算法
IT猿手1 小时前
多目标应用(一):多目标麋鹿优化算法(MOEHO)求解10个工程应用,提供完整MATLAB代码
开发语言·人工智能·算法·机器学习·matlab
青春男大1 小时前
java栈--数据结构
java·开发语言·数据结构·学习·eclipse
88号技师1 小时前
几款性能优秀的差分进化算法DE(SaDE、JADE,SHADE,LSHADE、LSHADE_SPACMA、LSHADE_EpSin)-附Matlab免费代码
开发语言·人工智能·算法·matlab·优化算法
我要学编程(ಥ_ಥ)2 小时前
一文详解“二叉树中的深搜“在算法中的应用
java·数据结构·算法·leetcode·深度优先
埃菲尔铁塔_CV算法2 小时前
FTT变换Matlab代码解释及应用场景
算法
mashagua2 小时前
RPA系列-uipath 学习笔记3
笔记·学习·rpa
nikoni232 小时前
828考研资料汇总
笔记·其他·硬件工程
沐泽Mu3 小时前
嵌入式学习-QT-Day05
开发语言·c++·qt·学习
许野平3 小时前
Rust: enum 和 i32 的区别和互换
python·算法·rust·enum·i32