首页 > 编程语言 >算法学习笔记——二分搜索

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

时间:2024-06-02 11:57:47浏览次数:19  
标签:二分 arr int 笔记 算法 num 峰值 ans

二分搜索

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

  • arr[m] == num,则num存在
  • arr[m] > num,则 r = m - 1,缩小r的范围,继续往左二分
  • arr[m] < num,则l = m + 1,缩小l的范围,继续往右二分
// 保证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的位置进行判断就可以得出结果
// 保证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),防止运算数值溢出
// 保证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. 判断中间值的大小,当左侧数值>中间值,往左侧二分,而右侧数值>中间值,往右侧二分,如果两个都成立选其中一个就行
    // 峰值元素是指其严格大于左右相邻值的元素
    // 给你一个整数数组 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)

标签:二分,arr,int,笔记,算法,num,峰值,ans
From: https://blog.csdn.net/luck_lsj/article/details/139389363

相关文章

  • AI积累-算法的作用和分工
    算法的作用我有很多外卖需求,我有很多店、用户、外卖员的坐标,如何科学分配给每一个外卖员合理的任务和路线,让整个外卖系统的用户等待时间较短,这个需求的大概设计思路是什么?主要用到传统算法还是AI算法?为了科学分配每一个外卖员合理的任务和路线,以减少整个外卖系统的用户等待时......
  • Large Language Models are Zero-Shot Rankers for Recommender Systems论文阅读笔记
    LargeLanguageModelsareZero-ShotRankersforRecommenderSystems论文阅读笔记Abstract​ 本工作旨在调查作为推荐系统的排名模型的LLM的能力。我们首先将推荐问题形式化为一个条件排序任务,将顺序交互历史作为条件,并将其他候选生成模型检索到的项目作为候选项。为了解决LL......
  • 代码随想录算法训练营第第25天 | 216.组合总和III 、17.电话号码的字母组合
    今天的题比较简单,重点是在于剪枝216.组合总和III如果把组合问题理解了,本题就容易一些了。题目链接/文章讲解:https://programmercarl.com/0216.组合总和III.html视频讲解:https://www.bilibili.com/video/BV1wg411873x/***@param{number}k*@param{number}n*@retu......
  • 对算法思维提升的思考
    博主是一个喜欢胡思乱想的蠢蛋,我无论学什么都在想:1.我为什么要学这个:到底是为了考试升学,还是为了面试找工作,还是想在其他人面前装b2.学这个知识能给我带来哪些提升?3.为什么别人学的比我轻松?到底是因为笨,还是因为方法不对?还是有认知上的差距?已经刷了600+题,却还是感觉在原地踏步......
  • 【目标检测系列】基于yolov8的头部姿态估计算法
    基于yolov8的头部姿态估计算法1.头部姿态简介头部姿态估计(HeadPoseEstimation):通过一幅面部图像来获得头部的姿态角.在3D空间中,表示物体的旋转可以由三个欧拉角(EulerAngle)来表示:分别计算pitch(围绕X轴旋转),yaw(围绕Y轴旋转)和roll(围绕Z轴旋转),分别学名俯仰角......
  • 自媒体(2)--头条算法机制,从0到1打造自媒体
    头条号算法机制一,机器算法推荐?平台根据关键词及用户的行为指标等数据,对平台的内容进行分析和精准化推荐,把用户喜欢的内容推荐给用户,把好的内容进行多次展示推荐,以实现用户获取的是自己喜欢的内容并持续性在本平台消费内容的过程。1,算法的指标?①文字关键词文章的标题、......
  • 3DS MAX备忘笔记(命令-面和元素)
    面层级轮廓(2d):缩放轮廓不改变边之间的关系插入(2d):复制已有轮廓并放缩,且连接对应的点(插入的距离均匀,直接放缩面距离不均匀)挤出(3d):可选挤出方向、挤出后面之间是否还连接 倒角(3d): 挤出+插入(二维面上自动等距边界放缩),(直接缩放挤出的面不等距)桥:l 直接多选面,点桥:元素间—......
  • 3DS MAX备忘笔记(命令-选择命令)
    选择命令循环:l 双击边使用,选择首尾相接的一圈边。l 选择某面+按ctrl双击旁边的面使用。l 无法选择多边面的一圈边l 点循环的边:均匀间隔选择。选择某边+按下点循环l 点循环的面:=点循环边+按下ctrl时转面层级(面层级不能直接点循环)环形:l 选择平行的一圈边。选择......
  • 3DS MAX备忘笔记(命令-全层级通用)
    全层级可用命令重置变换:l 清除对模型变换操作的记录。(防止变换层级滞留影响后续精细操作)l 快速添加重置变换修改器:选定对象-实用程序-重置变换-重置选定内容,(添加重置变换后再CTRLz撤回可能出错)l 重置变换可以同时对多对象使用l 修改器搜索添加的重置变换不好使(???l ......
  • 语音降噪算法库介绍
    一.语音降噪技术方向介绍   软件上进行语音降噪目前主要是两个方向:传统降噪算法和AI降噪算法,他们各有千秋,目前看他们各有千秋,有各自适用场景。推荐一个不错的人工智能学习网站,通俗易懂,内容全面,作为入门科普和学习提升都不错,分享一下给大家:前言–人工智能教程1.两者的对......