C++算法——二分法查找

news2024/11/25 12:55:50

一、二分查找算法思想和模版

1.算法思想

2.细节处理

3.模板

二、二分查找

1.链接

704. 二分查找 - 力扣(LeetCode)

2.描述

3.思路

先从最经典的题目去切入,思路就是二分查找,这里我们认为,目标值既可以看作为左部分的后端,也可以认为是右部分的前端,当然有更简单的写法,就是直接判断相等,但那个方式对二分查找这一类题目的普适性不高,作为练习,我们这里采用目标值落在左边末端的情况

4.参考代码

认为目标值在左边末端的情况

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

三、在排序数组中查找元素的第⼀个和最后⼀个位置

1.链接

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

2.描述

3.思路

通过分析,这题我们需要找到target的开始和末尾,我们可以分别进行两次二分查找去分别找到开端和末尾,刚好对应着两种不同的策略和模版

target开端:我们将数据划分成 【 小于target的数 】【target开端 和大于等于target的数 】 ,此时目标数据在后半段的开端

target后端:数据划分成【小于等于target的数,target末尾】【大于target的数】,此时目标值在前半段的末端

当然也要考虑不存在target的情况,在第一次找开端时,若是没找到,则可以直接返回{-1,-1}

4.参考代码

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) 
    {
        //由于有空数组,做个特殊处理
        if(nums.size() == 0)
        {
            return {-1,-1};
        }

        //寻找target开端
        int begin,end;
        int left = 0;
        int right = nums.size()-1;
        while(left < right)
        {
            int mid = left + (right - left)/2;
            if(nums[mid] < target) left = mid + 1;
            else right = mid;
        }
        if(nums[left] == target) begin = left;
        else return {-1,-1};

        //寻找target末尾
        right = nums.size()-1;
        while(left < right)
        {
            int mid = left + (right - left + 1)/2;
            if(nums[mid] <= target) left = mid;
            else right = mid - 1;
        }
        //由于开端已经找到,则说明一定存在target,末端也一定存在
        end = left;
        return {begin,end};
    }
};

四、搜索插入位置

1.链接

35. 搜索插入位置 - 力扣(LeetCode)

2.描述

3.思路

根据题意,我们不能看出使用二分查找的方法,根据题目意思,有两种情况

一种是目标值存在,那么和最简单的二分查找找目标值那题是一样的,采用哪种策略划分都可以

另一种是不存在则返回插入位置的索引,这个插入位置的索引原先是比target较大一点的值

因此我们将区域划分为【小于target的值】【大于等于target的值】,此时我们要找到目标索引就是后半部分的开端

此外,还需要考虑边界情况:

1.数组内的数全都大于target

最终,right在不断调整下,会落在0上,是满足题意的

2.数组内的数全都小于target

最终,left会落在right(最后一个位置的索引),但实际要求插入的位置是right+1的地方

所以这里做一个判断,若是最终出来的值小于target,则返回right+1(left+1)

4.参考代码

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

五、x的平方根

1.链接

69. x 的平方根 - 力扣(LeetCode)

2.描述

3.思路

根据题意,我们可以认为,目标值的范围,一定会是在【1,x】区间,我们根据这个区间内每个数的平方去划分前后两个区间【平方小于等于x的数】【平方大于x的数】,我们要找的目标值落在前半部分区间的末端

考虑边界情况,目标值一定会存在,但是x从0开始,因此,我们需要对x=0时的情况做一个特殊处理

4.参考代码

class Solution {
public:
    int mySqrt(int x) 
    {
        if(x == 0) return 0;
        int left = 1;
        int right = x;
        while(left < right)
        {
            long long mid = left + (right - left + 1)/2;
            if(mid*mid <= x) left = mid;
            else right = mid - 1;
        }
        return left;
    }
};

六、山脉数组的峰值索引

1.链接

852. 山脉数组的峰顶索引 - 力扣(LeetCode)

2.描述

3.思路

通过题意,我们可以将数据划分为这两种情况 【前半部分都是递增的数据】【后半部分全是递减的数据】,我们要找到目标值,可以认为是在前半部分的末端,也可以认为是后半部分的开端,任选一个即可

由于题目说一定是山峰数组且数组长度大于等于3,因此可以不考虑特殊情况

这题需要稍微分析的就是条件的判断:

若是认为目标值在前半段的末端,则在判断递增还是递减时,则需要前一个比较后一个

若是认为目标值在后半段开端,则判断递增还是递减时,需要后一个比较前一个

4.参考代码

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

七、寻找峰值

1.链接

162. 寻找峰值 - 力扣(LeetCode)

2.描述

3.思路

只需要找到数组中任意一个峰值即可,因此思路和上一题是一样的

4.参考代码

class Solution {
public:
    int findPeakElement(vector<int>& nums) 
    {

        int left = 0;
        int right = nums.size()-1;
        while(left < right)
        {
            int mid = left + (right - left + 1)/2;
            if(nums[mid] > nums[mid-1]) left = mid;
            else right = mid -1;
        }
        return left;
    }
};

八、搜索旋转排序数组中的最小值

1.链接

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

2.描述

3.思路

4.参考代码

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

九、点名

1.链接

LCR 173. 点名 - 力扣(LeetCode)

2.描述

3.思路

根据题意,我们知道,若是没有人缺席,下标和数字应该会严格的一一对应的,我们可以将数据划分为前后两段【下标和元素严格对应】【下标和元素没有对应】,我们的目标值就落在后半段的开端

还需要考虑一下边界条件,若是恰好最后一位同学缺席,此时该算法会算到倒数第二位学号的同学,此时在返回时做一个判断即可

return left == records[left] ? left+1:left ;

4.参考代码

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

总结

本章介绍了二分查找的算法思想,并且整理了相关的经典题目,从简单到难的去逐步递进,并且提供了链接和描述,可以直接通过链接去练习,或者直接看本篇博客去尝试思考解题,还提供了参考的思路,部分困难的题目会结合图像去分析,还有测试通过的参考代码

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

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

相关文章

Oracle基础【7-Oracle中RMAN恢复管理器】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;Oracle从基础到进阶 本文对应Oracle实验报告源文件下载&#xff1a;公众号程序员刘同学回复oracle实验获取下载链接 实验七 RMAN恢复管理器一、实验目的二、实验环境三、实验内容1 为备份…

第12章 集合框架

一 集合框架概述 1.1 生活中的容器 1.2 数组的特点与弊端 一方面&#xff0c;面向对象语言对事物的体现都是以对象的形式&#xff0c;为了方便对多个对象的操作&#xff0c;就要对对象进行存储。另一方面&#xff0c;使用数组存储对象方面具有一些弊端&#xff0c;而Java 集合…

WebGIS 地铁交通线网 | 图扑数字孪生

数字孪生技术在地铁线网的管理和运维中的应用是一个前沿且迅速发展的领域。随着物联网、大数据、云计算以及人工智能技术的发展&#xff0c;地铁线网数字孪生在智能交通和智慧城市建设中的作用日益凸显。 图扑软件基于 HTML5 的 2D、3D 图形渲染引擎&#xff0c;结合 GIS 地图…

OmniGraffle Pro for mac 出色的图形设计软件

OmniGraffle Pro是一款非常出色的图形设计软件&#xff0c;它主要适用于Mac和iPad平台&#xff0c;可以用来轻松绘制各种精美的图表、示意图和界面设计。 软件下载&#xff1a;OmniGraffle Pro for mac中文注册激活版 以下是OmniGraffle Pro的一些主要特点和功能&#xff1a; 界…

JavaScript常用知识面试题day01

大家好我是没钱的君子下流坯&#xff0c;用自己的话解释自己的知识 前端行业下坡路&#xff0c;甚至可说前端已死&#xff0c;我还想在前段行业在干下去&#xff0c;所以从新开始储备自己的知识。 从CSS——>Javascript——>VUE2——>Vuex、VueRouter、webpack——>…

【学习笔记】java项目—苍穹外卖day09

文章目录 用户端历史订单模块1. 查询历史订单1.1 需求分析和设计1.2 代码实现1.2.1 user/OrderController1.2.2 OrderService1.2.3 OrderServiceImpl1.2.4 OrderMapper1.2.5 OrderMapper.xml1.2.6 OrderDetailMapper 1.3 功能测试 2. 查询订单详情2.1 需求分析和设计2.2 代码实…

HTML代码加固:保障网站安全

引言 HTML是网站开发的基础语言&#xff0c;它的安全性直接关系到网站的安全性。为了保障网站的安全性&#xff0c;我们需要加固HTML代码。本文将介绍一些具体方法&#xff0c;帮助你加固HTML代码&#xff0c;提高网站的安全性。 摘要 本文将介绍以下几种方法来加固HTML代码…

新能源汽车充电桩主板产业链解析

新能源汽车充电桩主控制板&#xff0c;简称汽车充电桩主板&#xff0c;是充电桩设施的核心部件&#xff0c;主要负责控制充电桩的整体运行和管理充电过程。了解汽车充电桩主板的整体产业链是非常重要的&#xff0c;这可以帮助您更好地了解供应链、采购渠道以及行业发展趋势。 产…

【C++】二分查找算法(模板)

重点 只需要记住两点&#xff1a; 1.left right 时&#xff0c;一定就是最终结果&#xff08;包括找不到目标值&#xff09;&#xff0c;无需再次判断&#xff0c;如果判断就会死循环 2.求中点如果是求左端点 mid left (right - left)/2 如果是求右端点 mid left (right -…

HTTP/UDP/TCP/IP网络协议

文章目录 计算机网络基础HTTPUDPTCP连接管理(三次握手/四次挥手)TCP可靠传输(确认答应)超时重传滑动窗口流量控制拥塞控制延时应答捎带应答粘包问题其他 IP数据链路层MUT 相关问题TCP会粘包、UDP永远不会粘包 学习博客 计算机网络基础 OSI模型定义了网络互连的七层框架&#x…

深度学习平台

深度学习平台(只能有线连接校园网) 账户 yeguifeng密码 yguifengenv3 : pytorch1.9cudajupytermatplotlib pycuda: pycuda Timesformer –data_dir ./trainingVideo --category my_fire --output_dir ./output --image_size 100 --num_chain 10 --batch_size 14 --lr 0.001…

Android Monkey自动化测试

monkey一般用于压力测试&#xff0c;用户模拟用户事件 monkey 基本用法 adb shell monkey [参数] [随机事件数]monkey常用命令 -v&#xff1a;用于指定反馈信息级别&#xff0c;总共分三个等级-v -v -vadb shell mokey -v -v -v 100-s&#xff1a;用于指定伪随机数生成器的种…

vue3源码解析——watch和watchEffect区别

watch和watchEffect是Vue 3.0中新增的两个响应式API&#xff0c;用于监听数据的变化。watch适用于需要获取新值和旧值&#xff0c;或者需要懒执行的场景&#xff0c;而watchEffect适用于需要监听多个数据源&#xff0c;并且需要立即执行的场景。它们之间的区别如下&#xff1a;…

OSPF-路由过滤、OSPFv3

OSPF——过滤&#xff0c;故障排除 OSPFv2——路由过滤 1、路由引入的过滤&#xff1a; import-route static route-policy //用于实现路由引入的过滤 filter-policy export&#xff0c;针对本区域传出的路由执行过滤 filter-policy import&#xff0c;针对传入本区域的路…

STM32学习和实践笔记(4): 分析和理解GPIO_InitTypeDef GPIO_InitStructure (a)

深入分析及学习一下上面这一段代码的构成与含义。 首先&#xff0c;这个GPIO_InitTypeDef GPIO_InitStructure;其实与int a 是完全类似的语法格式以及含义。 GPIO_InitStructure就相当于a这样一个变量。不过从这个变量的名字可以知道&#xff0c;这是一个用于GPIO初始化的结构…

部署项目遇到的各种问题总结

文章目录 前言一、后端问题 jar包运行出现错误宝塔面板使用jdk17二、数据库问题 版本问题三、前端问题 连不上后端总结 前言 在做完项目之后&#xff0c;为了让别人访问到自己的网站&#xff0c;就需要部署前端后端以及数据库&#xff0c;但是在部署的过程中出现了各种问题和困…

AcWing 786. 第k个数——算法基础课题解

AcWing 786. 第k个数 题目描述 给定一个长度为 n的整数数列&#xff0c;以及一个整数 k&#xff0c;请用快速选择算法求出数列从小到大排序后的第 k 个数。 输入格式 第一行包含两个整数 n 和 k。 第二行包含 n 个整数&#xff08;所有整数均在 1∼10^9 范围内&#xff09…

用于无人机小型化设计的高精度温补晶振

用于无人机小型化设计的高精度温补晶振:TG2016SMN和TG2520SMN。无人机的发展可以说是非常的迅速&#xff0c;在安防&#xff0c;农业&#xff0c;交通&#xff0c;电力&#xff0c;直播等领域经常能看到无人机大显身手。无人机的应用场最是非常的广泛&#xff0c;功能更强&…

[蓝桥杯练习]通电

kruskal做法(加边) #include <bits/stdc.h> using namespace std; int x[10005],y[10005],z[10005];//存储i点的x与y坐标 int bcj[10005];//并查集 struct Edge{//边 int v1,v2; double w; }edge[2000005]; int cmp(Edge a, Edge b){return a.w < b.w;} int find(i…

数控加工4轴初探

4轴加工之前一直觉得很神秘&#xff0c;最近画了些时间研究了一下&#xff0c;做过之后发现起始也不是特别复杂。 图中是两步&#xff0c;一步是粗开&#xff0c;已不是用指形铣刀精加工螺旋槽。