【C++例题 / 训练】二分算法(模板 例题)

news2024/11/26 4:25:38

引言

二分也就是二分查找,又叫折半查找。这种算法正如其名,每一次都要分一半。

二分算法可以分为二分查找和二分答案。

以在一个升序数组中查找一个数为例,每次考察数组当前部分的中间元素,如果中间元素刚好是要找的,就结束搜索过程;如果中间元素小于所查找的值,那么左侧的只会更小,不会有所查找的元素,只需到右侧查找;如果中间元素大于所查找的值同理,只需到左侧查找 

二分法的使用条件

二分法是适用于解决具有“二段性”(单调性)的问题的方法,通常表现为求解满足某一条件的最大值或者最小值

  1. 上下界确定。 我们可以通过上下界的折半来优化查找。
  2. 二段性: 对某一范围内的数据,存在一个临界点,使得临界点某一侧的所有数据都满足某一性质,另一侧的所有数据都不满足这一性质,就称这一范围内的数据具有二段性。

二段性包括单调性,即区间内有序,这样二分出来的结果是严格大于或者小于或等于target的。
但是,二段性也体现在非单调性上,也称为局部有序,可以参考 162. 寻找峰值 和 33. 搜索旋转排序数组。由这些题我们可以得知,二分法的奥义(本质)不在于单调性,而是二段性。也就是我们能对整体无序但局部有序的序列进行二分法。

二分的前提条件

1、答案在一个区间内(一般情况下,区间会很大,暴力超时)

2、直接搜索不好搜,但是容易判断一个答案可行不可行

3、该区间对题目具有单调性,即:在区间中的值越大或越小,题目中的某个量对应增加或减少。

4、若有多个答案满足题意,则这些答案具有如下特点:若答案 x 满足,则答案范围内小于 x 或大于 x 的答案均满足。

模板

🥑1 朴素版

while (l <= r)
{
    int mid = (r - l) / 2 + l;  //防止溢出,和mid = (r - l + 1) / 2 + l;等价
    if (...) l = mid + 1;
    else if (...) r = mid - 1;
    else return ...;
}

🍉2 求大于等于目标的最小值(查找区间左端点)

while (l < r) //区间不为空
{
    int mid = ((r - l) >> 1) + l;
    if (...) l = mid + 1;  
    else r = mid;
}

🥝3 求小于等于目标的最大值(查找区间右端点)

while (l < r)
{// 当l,r相邻时,会l=mid,<r,死循环,模板1不影响,因为l=mid+1=r 
    int mid = ((r - l + 1) >> 1) + l;
    if (...) l = mid;
    else r = mid - 1;

例题

1. 二分查找

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int l = 0, r = nums.size() - 1;
        while (l <= r)
        {
            //int mid = (r - l) / 2 + l; //朴素版本下 两个都行
            int mid = (r - l + 1) / 2 + l;
            if (nums[mid] == target) return mid;
            else if (nums[mid] > target) r = mid - 1;
            else l = mid + 1;
        }
        return -1;
    }
};

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

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) 
    {
        if (nums.size() == 0) return { -1,-1 };
        int begin = 0;
        // 1. 二分左端点
        int l = 0, r = nums.size() - 1;
        while (l < r) //区间不为空
        {
            int mid = ((r - l) >> 1) + l;
            if (nums[mid] < target)l = mid + 1;
            else r = mid;
        }
        // 判断是否有结果
        if (nums[l] != target) return { -1,-1 };
        else begin = l; //标记左端点
       
        l = 0, r = nums.size() - 1;
        while (l < r) //区间不为空
        {
            int mid = ((r - l + 1) >> 1) + l;
            if (nums[mid] > target) r = mid - 1;
            else l = mid;
        }

        return { begin, r};
    }
};


3. x 的平方根 

class Solution {
public:
    int mySqrt(int x) {
        if (x < 1) return 0;
        int l = 1, r = x;
        while (l < r) //精度保证
        {
            long long mid = (r - l + 1) / 2 + l; //防止溢出
            if (mid * mid <= x) l = mid;
            else r = mid - 1;
        }
        return l;
    }
};

4. 搜索插入位置

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int l = 0, r = nums.size();
        while (l < r)
        {
            int mid = (r - l) / 2 + l;
            if (nums[mid] < target) l = mid + 1;
            else r = mid;
        }
        return l;
    }
};

5. 山脉数组的峰顶索引

思路:

 该题仍具有二段性,左边递增,右边递减,用二分查找算法,

当前山峰高于左边山峰,区间往右缩小,否则往左缩小

注:封顶的左边区间,一定是递增的,因此套用模板三即可,找最右端点

class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr) {
        int l = 1, r = arr.size() - 2;
        while (l < r)
        {
            int mid = l + (r - l + 1) / 2;
            if (arr[mid] > arr[mid - 1]) l = mid;
            else r = mid - 1;
        }
        return r;
    }
};

6、寻找峰值

思路:

该题相比于上题,该题有多个峰值存在,故在两个封顶之间的区间内,从左到右一定递增,故套用模板二,找区间左端点即可。

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        int l = 0, r = nums.size() - 1;
        while (l < r) // 左边如果不大于右边,则
        {
            int mid = (r - l) / 2 + l;
            if (nums[mid] > nums[mid + 1]) r = mid ; 
            else l = mid + 1;
        }
        return l;
    }
};

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

思路:

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

8. 点名

思路:

按照缺失的数分为左右两个区间。

左边,nums[i] == i (left = i + 1)

右边 nums[i]  > i. (right = i)

注:当缺失的数是最后一个数,需要做下特殊判断,因此r 从 n 开始

class Solution {
public:
    int takeAttendance(vector<int>& records) {
        int l = 0, r = records.size();
        while (l < r)
        {
            int mid = (r - l) / 2 + l;
            if (records[mid] == mid) l = mid + 1;
            else r = mid;
        }
        return l;
    }
};

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

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

相关文章

王牌功能 | 法大大“证据管理”,让关键数据坚不可摧!

到底还能不能好好签合同… 法大大证据管理功能&#xff0c;基于电子合同签署全流程&#xff0c;为使用法大大电子签的机构及个人用户提供互联网数据电文的实时存证&#xff0c;并由第三方机构进行证据固化&#xff0c;将存证的数据电文转化成可读性更高、具有司法效力的证明材料…

多线程、多进程,还是异步?-- Python 并发 API 如何选择

如何选择正确的 Python 并发 API模块 &#xff1f; Python 标准库提供了三种并发 API &#xff0c; 如何知道你的项目应该使用哪个 API&#xff1f; 在本教程将带逐步了解各API的特性、区别以及各自应用场景&#xff0c;指导你选择最合适的并发 API。 多线程、多进程&#xff0…

音频采集spring_ws_webrtc (html采集麦克风转gb711并发送广播播放)完整案例

下载地址&#xff1a;http://www.gxcode.top/code 项目说明 springbootwebscoektwebrtc 项目通过前端webrtc采集麦克风声音&#xff0c;通过websocket发送后台&#xff0c;然后处理成g711-alaw字节数据发生给广播UDP并播放。 后台处理项目使用线程池(5个线程)接受webrtc数据并…

JAVA基础:字节字符转换流

前言 当我们使用流读取数据时&#xff0c;如果这个数据中含有中文&#xff0c;我们对这个数据进行操作就会出现乱码问题&#xff0c;这时候我们要使用字节字符转换流来处理一下数据。 字节字符转换流 字节字符转换流是一个过程流 字节字符转换流是一个字符流&#xff0c;所…

如何为 SEO 做关键词优化

关键词优化是一种基本的 SEO 技术&#xff0c;可以提高你的网站在搜索结果中的可见度&#xff0c;并吸引更多的访问者。 在这份关键词优化指南中&#xff0c;我们将分享在 SEO 的这一方面脱颖而出所需的知识、技巧和技巧。使用本指南可以超越您的竞争对手&#xff0c;并为您的…

一文搞懂数据标注

hihi,大家好,最近开始和内容那个团队研究SD出图了,作为家具家电行业的小牛人,除了研究SD和ComfyUI本身,需要了解算法同学如何进行模型微调的,因为用的是开源的底座,预训练部分就不深入介绍了,重点看一下二次预训练,在这个过程中有一个环节比较关注就是小规模数据集,也…

【java】RuoYi-Vue前后端分离版本-请求被拦截,怎么修改拦截过滤器,解决方案

【java】RuoYi-Vue前后端分离版本-请求被拦截&#xff0c;怎么修改拦截过滤器 它用到了一个安全管理框架Spring Security 你可以通过这篇文章《Spring Security 详解》 去了解它&#xff0c;怎么使用或者使用原理。 所有业务都受SecurityConfig配置所过滤 SecurityConfig配置…

2024年思维导图工具怎样可以轻松选择

思维导图&#xff0c;作为一种直观、有效的思维工具&#xff0c;凭借其强大的信息整理能力和创意激发潜力&#xff0c;逐渐成为了人们学习、工作和生活中不可或缺的一部分。今天&#xff0c;就让我们一起走进这个充满智慧的领域&#xff0c;探索那些2024年大家都在使用的思维导…

Cleer耳机好不好用?南卡、Cleer、飞利浦、倍思横评对比

​大家好&#xff0c;作为一位多年的数码博主和耳机发烧友&#xff0c;最近后台收到不少私信&#xff0c;都是小伙伴想让我测评一下最近很火热的开放式耳机&#xff0c;那么为了回馈大家这么久的支持&#xff0c;说做就做&#xff01;我买了最近网上很热门的几款开放式耳机&…

电线 硬线 和软线 连接

电线 硬线 和软线 连接 首先把软线&#xff0c;拧成一股&#xff0c;然后搭到硬线上回转一圈&#xff0c;这里要注意线头往反向回转&#xff0c;大家看下图中的软线&#xff0c; 再在硬线上缠绕7—8圈&#xff0c;根据线的长短&#xff0c;过长就剪去一些。 最后将硬导线往后弯…

【速览】设计模式(更新中)

目录 一、背景二、优缺点优点缺点 三、适用场景四、核心组成创建型模式 Creational Design Pattern 5结构型模式 Structural Design Patterns 7行为型模式 Behavioral Design Patterns 11’ 五、底层原理六、对比参考 一、背景 这个技术出现的背景、初衷和要达到什么样的目标或…

【Python开发实践】在线商城系统——需求及需求分析

项目背景及需求 这个练习项目的设置背景是一家图书销售公司&#xff0c;为了扩大销售渠道&#xff0c;想要开通网上商城&#xff0c;利用在线博客和电子商城来销售图书。 具体需求如下&#xff1a; 每个商品可以留言 实现在线购物车处理和订单处理 实现对产品、购物车和订单的…

python | 图片转换为 pdf 实现方法

目录 一、PIL 库简介及安装使用方法 &#xff08;一&#xff09;python 不同版本下 PIL 的使用方法 二、图片转换为 pdf 的两种实现方法 &#xff08;一&#xff09;简易版——pdf 页面尺寸跟随图片大小 &#xff08;二&#xff09;常用版——pdf 每页尺寸统一为 A4 一、P…

C#PACS系统源码,影像存档与传输系统源码,数字化医学影像系统源码,三维重建影像PACS系统源码

C#PACS系统源码&#xff0c;影像存档与传输系统源码&#xff0c;数字化医学影像系统源码&#xff0c;三维重建影像PACS系统源码 PACS即影像存档与传输系统&#xff08;Picture Archiving and Communication System&#xff09;&#xff0c;是医学影像、数字化图像技术、计算机技…

C++遍历for_each

#include <iostream> #include <stack> #include <vector> #include <algorithm> using namespace std; //打印数组 class bianli { public:void operator()(int val){cout << val << " ";} }; void printVector(int val) {cout…

【经验分享】将ui文件转化成py代码

目录 先写一个简单的ui界面 将ui文件另存为 将UI文件转换为py代码 测试一下你生成的py文件 &#x1f31f; 嗨&#xff0c;我是命运之光&#xff01; &#x1f30d; 2024&#xff0c;每日百字&#xff0c;记录时光&#xff0c;感谢有你一路同行。 &#x1f680; 携手启航&…

第R2周:LSTM-火灾温度预测

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 一、什么是LSTM 1.LSTM的本质 长短时记忆网络&#xff08;Long Short-Term Memory, LSTM&#xff09;的本质是一种特殊的循环神经网络&#xff08;Recurrent…

《Cloud Native Data Center Networking》(云原生数据中心网络设计)读书笔记 -- 05网络虚拟化

本章帮助网络工程师或架构师回答如下问题&#xff1a; 什么是网络虚拟化?网络虚拟化有哪些用途?网络虚拟化领域内有哪些不同的技术方向?网络虚拟化的控制面有哪些选择?当使用 VXLAN 时如何进行桥接和路由&#xff1f; 什么是网络虚拟化&#xff1f; 网络虚拟化可以让网络…

揭秘!格行如何成为随身WiFi界的‘比亚迪’!如何成为随身WiFi热销第一名?

比亚迪把续航超过2000km的油车打入了10万元以内&#xff01;创造历史&#xff01; 为什么这么说&#xff1f;还不是因为这两辆车都搭载了比亚迪最新研发的第五代 Dmi 混动技术。这项技术有多“逆天”&#xff1f;直接创下了三项全球之最——全球最高发动机热效率、百公里最低油…

CUDA C++ 最佳实践指南

CUDA C 最佳实践指南 (nvidia.com)https://docs.nvidia.com/cuda/cuda-c-best-practices-guide/index.html#getting-started2. 异构计算 CUDA 编程涉及在两个不同的平台上同时运行代码&#xff1a;具有一个或多个 CPU 的主机系统和一个或多个支持 CUDA 的 NVIDIA GPU 设备。 …