专题三——二分算法

news2024/12/29 17:58:30

目录

原理

模板

朴素二分算法

非朴素二分算法

一二分查找

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

三点名

四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 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

实景三维在文化旅游领域的应用

实景三维技术&#xff0c;作为一种前沿的科技手段&#xff0c;近年来在文化旅游领域的应用逐渐崭露头角。它能够将真实世界的场景以三维的形式精确呈现&#xff0c;为游客带来身临其境的体验&#xff0c;为文化旅游注入新的活力。本文将探讨实景三维在文化旅游领域的应用及其所…

编程新手必看,学习python中数字数据类型内容(7)

Python中的数字数据类型主要包括以下几种&#xff1a; 整数&#xff08;int&#xff09;&#xff1a;这是最基本的数字类型&#xff0c;用于表示整数值&#xff0c;如1、-5和1000等。在Python中&#xff0c;整数可以处理任意大小的数值&#xff0c;并且支持多种数学运算。 浮点…

Windows与Linux路径分隔符对比及Java代码实战

在Windows中&#xff0c;磁盘中用反斜杠&#xff08;又称为右斜杠&#xff09;\表示路径的分隔。在浏览器中用正斜杠/来表示路径的分隔。 Linux则是统一用/表示路径的分隔的。下面给出Linux中一些常见的路径表示&#xff1a; / 表示根目录./ 表示当前目录…/ 表示上级目录 …

【C++】C++中的stack和queue

一、概述 本篇blog写明了介绍的是STL(标准模板库)中的stack和queue&#xff0c;栈和队列虽然在处理数据的方式上有明显的不同&#xff0c;但它们作为操作受限的线性数据结构&#xff0c;在学习和应用中经常被放在一起讨论&#xff0c;以便更全面地理解数据结构的概念和使用。 在…

Windows瘦客户机专用系统安装教程

前言 小白偶然看到微软有给瘦客户机定制了专用系统Windows Thin PC x86。 从名字就可以看出来&#xff0c;瘦客户机的系统是32位的&#xff0c;安装完系统之后可以用来干啥&#xff0c;咱们很多小伙伴估计都不清楚。 首先要了解&#xff1a;什么是瘦客户机&#xff1f; 瘦客户…

逐步学习Go-WaitGroup【连字都懒得写了,直接Show my Code】

package waitgroup_testimport ("fmt""runtime""sync""testing""time""github.com/stretchr/testify/assert" )// 这是对Go语标准库中sync包下的WaitGroup的描述。// WaitGroup用于等待一组并发的goroutine结结束…

争相上市,黑芝麻智能和地平线,能突出重围吗?

图片&#xff5c;freeflo.ai ©自象限原创 作者丨罗辑 中国最有代表性两家自动驾驶大算力芯片&#xff08;SoC&#xff09;公司在港交所相遇了。 3月23日&#xff0c;黑芝麻智能向港交所递交主板上市申请&#xff1b;3天之后&#xff0c;地平线也向港交所递交了招股书。…

基于Springboot的少儿编程管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的少儿编程管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

二极管特性介绍

二极管 贴片二极管 不同封装的二极管 二极管不同的符号 二极管的结构组成 二极管就是由一个PN结加上相应的电极引线及管壳封装而成的。 采用不同的掺杂工艺&#xff0c;通过扩散作用&#xff0c;将P型半导体与N型半导体制作在同一块半导体&#xff08;通常是硅或锗&#xff…

【前端面试3+1】08 css选择器、在前端页面展示后端传来的图片数组、请求方法的常见类型、【搜索插入位置】

一、css选择器有哪些&#xff1f; 1.元素选择器&#xff1a; 通过元素名称选择元素。 示例&#xff1a;p 选择所有段落元素。 2.类选择器&#xff1a; 通过类名选择元素。 示例&#xff1a;.btn 选择所有类名为 btn 的元素。 3.ID选择器&#xff1a; 通过id属性选择元素。 示例…

Adobe Bridge 2024:连接创意,探索无限可能 mac/win版

Adobe Bridge 2024&#xff0c;作为Adobe家族中的一款强大的创意管理工具&#xff0c;再次革新了数字资产管理和工作流程优化的标准。这款软件不仅继承了Adobe Bridge一贯的直观界面和强大功能&#xff0c;更在多个方面进行了突破性的改进。 Bridge 2024软件获取 全面的资源管…

软考之零碎片段记录(六)+复习巩固

A. 上新 一、关系模式 1. 决定属性 AB->C,函数依赖左侧出现为决定属性 AB->C,函数依赖右侧出现为非决定属性 候选键在决定属性中挑选&#xff0c;AB->C, CD->B中&#xff0c;A,D为侯选建 二、授权SQL 将权限授予用户&#xff08;grant <权限> on&#xf…

Git安装教程(图文安装)

Git Bash是git(版本管理器)中提供的一个命令行工具&#xff0c;外观类似于Windows系统内置的cmd命令行工具。 可以将Git Bash看作是一个终端模拟器&#xff0c;它提供了类似于Linux和Unix系统下Bash Shell环境的功能。通过Git Bash&#xff0c;用户可以在Windows系统中运行基于…

【个人笔记】如何用 Python 编写激活码解锁程序,方法二

目录 前言 第一步&#xff1a;编写激活码解锁程序&#xff08;激活码.py&#xff09; 第二步&#xff1a;修改需要解锁的程序&#xff08;1.py&#xff09; 总结 前言 在软件开发中&#xff0c;有时我们需要设计一种机制来保护程序&#xff0c;例如通过激活码来控制程序的…

【MySQL】:深入解析多表查询(上)

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; MySQL从入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. 多表关系1.1 一对多1.2 多对多1.3 一对一 二. 多表查询概述2.1 概述2.2 分类…

C51实现每秒向电脑发送数据(UART的含义)

其实核心的问题是&#xff1a;串口的通信方式 异步串行是指UART&#xff08;Universal Asynchronous Receiver/Transmitter&#xff09;&#xff0c;UART包含TTL电平的串口和RS232电平的串口 UART要实现异步通信的&#xff1a; UART是异步串行接口&#xff0c;通信双方使用时…

2024唐山国际门窗幕墙展览会

2024唐山国际门窗幕墙展览会 2024TangshanInternational Door and Window Curtain Wall Exhibition 2024年6月14-16日 地点&#xff1a;唐山南湖国际会展中心 唐山国际门窗幕墙博览会一 年一届&#xff0c;深耕京津冀核心区域&#xff0c;专注门窗行业高质量 发展&#x…

网络协议——HTTP协议

目录 ​编辑 一&#xff0c;HTTP协议基本认识 二&#xff0c;认识URL 三&#xff0c;http协议的格式 1&#xff0c;发送格式 2&#xff0c;回应格式 四&#xff0c;服务端代码 五&#xff0c;http报文细节 1&#xff0c;Post与Get方法 2&#xff0c;Content_lenth 3&…

基于Springboot的航班进出港管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的航班进出港管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结…

C++的 stack和queue 的应用和实现【双端队列的理解和应用】

文章目录 stack的理解和应用栈的理解栈的模拟实现string实现stackvector实现stack queue的理解和应用队列的理解队列的模拟实现 双端队列原理的简单理解deque的缺陷为什么选择deque作为stack和queue的底层默认容器STL标准库中对于stack和queue的模拟实现stack的模拟实现queue的…