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

二分搜索

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

相关推荐
香菜大丸8 分钟前
链表的归并排序
数据结构·算法·链表
jrrz08288 分钟前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
oliveira-time20 分钟前
golang学习2
算法
黑叶白树33 分钟前
简单的签到程序 python笔记
笔记·python
@小博的博客35 分钟前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习
幸运超级加倍~1 小时前
软件设计师-上午题-15 计算机网络(5分)
笔记·计算机网络
南宫生1 小时前
贪心算法习题其四【力扣】【算法学习day.21】
学习·算法·leetcode·链表·贪心算法
懒惰才能让科技进步2 小时前
从零学习大模型(十二)-----基于梯度的重要性剪枝(Gradient-based Pruning)
人工智能·深度学习·学习·算法·chatgpt·transformer·剪枝
Ni-Guvara2 小时前
函数对象笔记
c++·算法
love_and_hope2 小时前
Pytorch学习--神经网络--搭建小实战(手撕CIFAR 10 model structure)和 Sequential 的使用
人工智能·pytorch·python·深度学习·学习