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

二分搜索

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

相关推荐
testpassportcn6 分钟前
UiPath-ADPV1 認證介紹|Automation Developer Professional v1
网络·学习·改行学it
玄冥剑尊6 分钟前
贪心算法进阶
算法·贪心算法
生擒小朵拉6 分钟前
ROS1学习笔记(二)
笔记·学习
玄冥剑尊8 分钟前
贪心算法深化 I
算法·贪心算法
52Hz11812 分钟前
力扣73.矩阵置零、54.螺旋矩阵、48.旋转图像
python·算法·leetcode·矩阵
BHXDML15 分钟前
第一章:线性回归& 逻辑回归
算法·逻辑回归·线性回归
iAkuya1 小时前
(leetcode)力扣100 二叉搜索树种第K小的元素(中序遍历||记录子树的节点数)
算法·leetcode·职场和发展
Root_Hacker1 小时前
include文件包含个人笔记及c底层调试
android·linux·服务器·c语言·笔记·安全·php
Remember_9932 小时前
【LeetCode精选算法】滑动窗口专题二
java·开发语言·数据结构·算法·leetcode
Gorgous—l2 小时前
数据结构算法学习:LeetCode热题100-动态规划篇(下)(单词拆分、最长递增子序列、乘积最大子数组、分割等和子集、最长有效括号)
数据结构·学习·算法