专题三——二分算法

目录

原理

模板

朴素二分算法

非朴素二分算法

一二分查找

二在排序数组中查找元素的第一个和最后一个位置

三点名

四x的平方根

五搜索插入位置 

六山脉数组的峰顶索引

七寻找峰值 

八寻找旋转排序数组中的最小值


原理

定义两个指针:left指向数组第一个元素,right指向数组的最后一个元素;通过某种条件的判断,让left与right向之间靠拢;最终left与right所指的元素来确定最后的答案

模板

二分算法的实现有两个模板:朴素二分算法与非朴素二分算法

朴素二分算法

while(left <= right)
{
    int middle = left+(right-left)/2 //写成(right-left)/2有越界的风险
    if(...)
    {
        left =middle + 1; 
    }
    else
    {
        right = middle - 1;
    }

}

非朴素二分算法

//左端点
while(left < right) //left <= right会越界
{
    int middle = left + (right - left) / 2;//left +(right - left + 1) /2会死循环
    if(...)
    {
        left = middle + 1;
    }
    else
    {
        right = middle;
    }

}

//右端点
while(left < right) //left <= right会越界
{
    int middle = left + (right - left +1) / 2;
    if(...)
    {
        left = middle;
    }
    else
    {
        right = middle - 1;
    }

}

大部分情况的二分算法题用的都是非朴素二分算法模板来实现的!

一二分查找

oj链接:704. 二分查找 - 力扣(LeetCode)

思路:懂了模板直接套用朴素二分算法解决:

当nums[middle] < target ; left=middle + 1;else right = middle - 1

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0,right=nums.size()-1;
        while(left<=right)
        {
            int middle=left+(right-left)/2;//防溢出
            if(nums[middle]<target)
            {
                left=middle+1;
            }
            else if(nums[middle]>target)
            {
                right=middle-1;
            }
            else
            {
                return middle;              
            }
        }
        return -1;
    }
};

二在排序数组中查找元素的第一个和最后一个位置

oj链接:34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

朴素二分算法解决不了,用非朴素二分模板来解决:

题目要求第一个与最后一个位置,直接用两个非朴素模板求出与target相同的左右两个端点

class Solution 
{
public:
    vector<int> searchRange(vector<int>& nums, int target) 
    {
        //越界判断
        if(nums.size() == 0) return {-1 , -1};
        //开始元素下标(求左端点)
        vector<int> ans(2);
        int left = 0 , right = nums.size() - 1;
        while(left < right)
        {
            int middle = left + (right - left) / 2;
            if(nums[middle] < target) left = middle + 1;
            else right = middle;
        }
        //有可能没有target 
        if(nums[left] != target) return {-1 , -1};
        ans[0] = left;
        //最后元素下标(求右端点)
        //有的话在left的右边,left不用再次走到开始位置
        right = nums.size() -1;
        while(left < right)
        {
            int middle = left +(right - left +1) /2;
            if(nums[middle] <= target) left = middle;
            else right = middle -1;
        }
        ans[1] = right;
        return ans;
    }
};

三点名

oj链接:LCR 173. 点名 - 力扣(LeetCode)

思路:此题的思路有很多:等差数列求和,哈希表,异或...

但这道题给出的条件适合来用二分算法解决:

判断数值与下标是否对应来进行left与right的移动 

class Solution {
public:
    int takeAttendance(vector<int>& records) 
    {
        int left=0,right=records.size()-1;
        while(left<right)
        {
            int middle=left+(right-left)/2;
            if(middle==records[middle]) left=middle+1;
            else right=middle;
        }
        //有可能数组里面与下标都对应上了返回后一个数字->[0,1]
        if(records[left]==left) return left+1;
        return left;
    }
};

四x的平方根

oj链接:LCR 072. x 的平方根 - 力扣(LeetCode) 

思路:从[1,x]中来找出符合某数的平方根<=x:如果在里面的某个值的平方根>x的,说明目标值是在这个值的左边区域,缩小范围更新right的值:是要等于它还是在它前一个位置就要自己来画图分析了;最后用非朴素模板套进去就解决本道题的求

五搜索插入位置 

oj链接:LCR 068. 搜索插入位置 - 力扣(LeetCode)

思路: 套用非朴素模板解决,注意最后结果的处理

class Solution 
{
public:
    int searchInsert(vector<int>& nums, int target) 
    {
        int left = 0,right = nums.size() - 1;
        while(left < right)
        {
            int middle = left +(right -left)/2;
            if(nums[middle] < target) left = middle + 1;
            else right = middle;
        }
        //left与right走到数组最后的处理
        if(right == nums.size() - 1 && nums[right] < target) return right + 1;
        else return right;
    }
};

六山脉数组的峰顶索引

oj链接:LCR 069. 山脉数组的峰顶索引 - 力扣(LeetCode)

 思路:山脉数组将数组分为两个区间:

左半边是递增的:arr[i] > arr[i-1](包含峰值);右半边是递减的:arr[i] < arr[i-1](不包含)

有了这个二段性,我们就可以来利用二分算法来解决问题,使得最后left与right指向峰顶

class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr) 
    {
        int left = 0,right = arr.size() - 1;
        while(left < right)
        {
            int middle = left + (right - left + 1) / 2;
            //middle在左半区间
            if(arr[middle] > arr[middle - 1]) left = middle;
            //middle在右半区间
            else if(arr[middle] < arr[middle -1]) right = middle -1;
        }
        return left;
    }
};

七寻找峰值 

 oj链接:162. 寻找峰值 - 力扣(LeetCode)

思路:要找数组其中一个峰值转化为求数组的峰值,与上面思路是一样的!

class Solution {
public:
    int findPeakElement(vector<int>& nums) 
    {
        int left = 0,right =nums.size() - 1;
        while(left < right)
        {
            int middle = left + (right - left) / 2;
            if(nums[middle] < nums[middle+1]) left = middle + 1;
            else if(nums[middle] > nums[middle + 1]) right = middle;
        }
        return left;
    }
};

八寻找旋转排序数组中的最小值

oj链接:153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)

思路: 将旋转数组分为两段;AB段前n(旋转的次数)个数值;CD是剩余的个数;我们来拿最后一个元素(nums[n - 1])作参照物,有这样的一个规律:

AB段的值nums[i]一定>nums[n - 1];CD段的值nums[j]<=nums[n - 1];

有了二段性,我们就可以用二分算法来解决问题,只需来判断left与right的移动就完成

class Solution {
public:
    int findMin(vector<int>& nums) 
    {
        
        int left = 0,right = nums.size() - 1;
        while(left < right)
        {
            int middle = left + (right - left) / 2;
            
            if(nums[middle]>nums[nums.size()-1]) left=middle+1;
            else right=middle;
        }
        return nums[right];
    }
};

那上面的参照物能用最左边的数来解决吗?好像也类似?

问题转换为能过测试用例[1,2]和[2,1]来思考!(坑帮你们填了)QAQ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/519052.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Layui三级联动插件使用方法

Layui高版本中没有在提供三级联动这个动画了&#xff0c;而是封装成了一个插件&#xff0c;使用方式也很简单 官网 省市县区三级联动下拉选择器 layarea - Layui 第三方扩展组件平台 (layuion.com)https://dev.layuion.com/extend/layarea/#doc html页面约束 整个选择器需要…

【保姆级讲解如何安装与配置Node.js】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

HTML1:html基础

HTML 冯诺依曼体系结构 运算器 控制器 存储器 输入设备 输出设备 c/s(client客户端) 客户端架构软件 需要安装,更新麻烦,不跨平台 b/s(browser浏览器) 网页架构软件 无需安装,无需更新,可跨平台 浏览器 浏览器内核: 处理浏览器得到的各种资源 网页: 结构 HTML(超…

SRS 实时视频服务器搭建及使用

一、SRS 介绍 SRS是一个开源的&#xff08;MIT协议&#xff09;简单高效的实时视频服务器&#xff0c;支持RTMP、WebRTC、HLS、HTTP-FLV、SRT、MPEG-DASH和GB28181等协议。 SRS媒体服务器和FFmpeg、OBS、VLC、 WebRTC等客户端配合使用&#xff0c;提供流的接收和分发的能力&am…

【机器学习】机器学习创建算法第4篇:K-近邻算法,学习目标【附代码文档】

机器学习&#xff08;算法篇&#xff09;完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;机器学习算法课程定位、目标&#xff0c;K-近邻算法定位,目标,学习目标,1 什么是K-近邻算法,1 Scikit-learn工具介绍,2 K-近邻算法API。K-近邻算法&#xff0c;1.4 …

Java:接口应用(Clonable 接口和深拷贝)

目录 1.引例2.Object中clone方法的实现3.Cloneable接口讲解4.深拷贝和浅拷贝4.1浅拷贝4.2深拷贝 1.引例 Java 中内置了一些很有用的接口, Clonable 就是其中之一. Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 “拷贝”. 但是要想合法调用 clone 方法。必…

Qt | Qt 的重要文件简介(推荐)

一、项目文件(pro 文件)及其语法 1、项目文件(pro 文件)的作用是列举项目中的源文件, 2、pro 文件的语法形式为:“变量 操作符 值”,比如 QT += widgets,多个值之间使用空格分开。 3、pro 文件的注释:从“#”开始,直至本行结束。 4、pro 文件的操作符见下表 5、pro 文…

【美团笔试题汇总】2023-09-02-美团春秋招笔试题-三语言题解(CPP/Python/Java)

&#x1f36d; 大家好这里是KK爱Coding &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新美团近期的春秋招笔试题汇总&#xff5e; &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f…

使用 mitmproxy 抓包 grpc

昨天在本地执行 grpc 的 quick start&#xff08;python版本的&#xff09;&#xff0c;我了解 grpc 内部使用的是 HTTP2&#xff0c;所以我就想着抓包来试试&#xff0c;下面就来记录一下这个过程中的探索。 注意&#xff1a;我的电脑上面安装了 Fiddler Classic&#xff0c;…

数据结构day2--双向链表

双向链表: 即可以从头遍历到尾部和从尾部遍历到头部的链表&#xff0c;每个结点包括两个链域&#xff1a;前驱指针域和后继指针域&#xff0c;所以比起单向链表&#xff0c;其可以在任意一个结点访问前后两个结点 关于双向链表的一个完整步骤为&#xff1a; 创建一个表头结构…

微软detours代码借鉴点备注

comeasy 借鉴点1 Loadlibray的时间选择 注入库wrotei.dll&#xff0c;为了获取istream的接口&#xff0c;需要loadlibrary&#xff0c;但是在dllmain中是不建议这样做的。因此&#xff0c;动态库在dllmain的时候直接挂载了comeasy.exe的入口 //获取入口 TrueEntryPoint (i…

【其他】灾害预警,科技助力:手机地震预警功能设置指导

22024年4月3日7时58分在台湾花莲县海域遭遇了一场7.3级的强烈地震&#xff0c;震源深度12公里&#xff0c;震中位于北纬23.81度&#xff0c;东经121.74度&#xff0c;距台湾岛约14公里。震中5公里范围内平均海拔约-3560米。这场突如其来的自然灾害给当地居民的生活带来了巨大的…

【MATLAB】GA_BP神经网络时序预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~ 1 基本定义 GA_BP神经网络时序预测算法是一种结合了遗传算法(GA)和反向传播(BP)神经网络的时序预测方法。它利用了遗传算法的全局搜索和优化能力&#xff0c;以及BP神经网络的学习和逼近能力&#xff0c;可以更有效地预…

Qtxlsx第三方库的安装和使用

本文仅作为一个记录&#xff0c;安装QtXlsx方便操作excel&#xff0c;主要参考了这篇博文&#xff1a;https://blog.csdn.net/u014779536/article/details/111769792 1&#xff0c;下载安装Perl脚本Strawberry Perl for Windows&#xff0c;默认安装strawberry-perl-5.30.0.1-…

【Redis教程0x0F】Redis实战篇

Redis如何实现延迟队列&#xff1f; 延迟队列是指把当前要做的事情&#xff0c;往后推迟一段时间再做。延迟队列的常见使用场景有以下几种&#xff1a; 在淘宝、京东等购物平台上下单&#xff0c;超过一定时间未付款&#xff0c;订单会自动取消&#xff1b;打车的时候&#x…

ES6学习(五)-- Module 语法

文章目录 Module 语法1.1 痛点介绍(1) 异步加载(2) 私密(3) 重名(4) 依赖 1.2 解决方法(1) 解决异步加载问题(2) 解决私密问题(3) 重名解决方法(4) 解决依赖问题 1.3 模块化使用案例 Module 语法 之前js 出现的某些痛点&#xff1a; 在script 中引入的变量名不可以重复&#…

深入了解 Python 中标准排序算法 Timsort

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ Timsort&#xff1a;一个非常快速的、时间复杂度为 O ( n l o g n ) O (n \ log\ n) O(n log n)、稳健&#xff08;即不改变等值元素间的相对顺序&#xff09;的排序算法&#xff0c;在处理真实世界数…

蓝桥杯单片机真题实践篇

这里就不完全写思路过程代码什么的&#xff0c;这一篇文章就写我在训练真题中遇到的过程。 &#xff08;呜呜呜&#xff0c;时间不够辣&#xff0c;能做多少算多少吧....&#xff09; 十三届省赛题 问题1&#xff1a;数码管的数字消影不明显 &#xff08;参考&#xff1a;蓝…

ms-前端八股文

1、暂时性死区 是指在 JavaScript 中使用 let 或 const 声明变量时&#xff0c;变量在其声明之前不能被访问或使用的特性。 var可以变量提升&#xff08;在 JavaScript 中&#xff0c;变量声明提升是指在执行代码之前&#xff0c;变量声明会被提升到作用域的顶部。&#xff0…

SSM 项目学习(Vue3+ElementPlus+Axios+SSM)

文章目录 1 项目介绍1.1 项目功能/界面 2 项目基础环境搭建2.1 创建项目2.2 项目全局配置 web.xml2.3 SpringMVC 配置2.4 配置 Spring 和 MyBatis , 并完成整合2.5 创建表&#xff0c;使用逆向工程生成 Bean、XxxMapper 和 XxxMapper.xml2.6 注意事项和细节说明 3 实现功能 01-…