初识算法 · 二分查找(4)

目录

前言:

寻找峰值

题目解析

算法原理

算法编写

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

题目解析

算法原理

算法编写

寻找缺失的数字

题目解析

算法原理

算法编写


前言:

​本文的主题是二分查找,通过三道题目讲解,一道是寻找峰值,一道是搜索旋转排序数组的最小值,一道是0 - n-1中缺失的数字。
链接分别为:
162. 寻找峰值 - 力扣(LeetCode)

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

LCR 173. 点名 - 力扣(LeetCode)
题目分为三个部分讲解,一是题目解析,二是算法原理,三是算法编写,那么,话不多说,直接进行主题咯。


寻找峰值

题目解析

题目是给了我们一个数组,这个数组并不像我们之前的数组一样具有明显的二段性,这个数组可以说是一个完全无序的数组,而我们要寻找的,是满足大于左右两值的数的索引,那么暴力解法简直就是不用经过大脑的,直接遍历数组即可,只要满足大于i - 1和 i + 1就可以了。

那么时间复杂度是显而易见的,直接就是O(N)了。

但是我们没有利用题目的条件,虽然是无序的,但是峰值的条件是大于左右两边,我们可以利用这个条件,使用二分查找。

算法原理

题目的隐含条件,左右两端都是负无穷的,数组可以有二段性,为:

我们随便定义一个位置,如果arr[i] > arr[i + 1]的话,那么在左区间一定是存在答案的,因为从num[-1]开始是负无穷,此时我们可以套用查找左端点的二分模板,对于右边的端点同理,如果arr[i] < arr[i + 1],代表右边有答案,因为nums[n]也是负无穷的。

所以我们就可以直接进入到算法编写了。

算法编写

class Solution 
{
public:
    int findPeakElement(vector<int>& nums) 
    {
        int left = 0, 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;
    }
};

所以,不是非要有序的才会存在二段性,像这种完全无序的,也是会存在二段性的。


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

题目解析

题目看起来非常复杂,但是实际上非常简单,无非就是介绍如何旋转数组介绍的多了一点而已,题目给的条件有原来是一个升序排序的数组,并且每个元素都不相同,要让我们找到一个最小的值。

要找最小的值还不简单吗?直接一个for循环遍历就可以了。

但是题目还要求了使用logN的算法解决该问题。那就是典型的使用二分咯。

如果使用的是暴力就是O(N)了。

算法原理

二分查找算法的原理都是需要看是否存在二段性,如果存在二段性的话,我们就可以使用二分查找算法了。

注意,最开始的数组是有序的,所以我们可以这样分数组:

而我们要找的,不就是C这个点吗!如果mid的值大于了D,也就是在AB段,我们就应该让left = mid + 1,如果mid 的值 < D,也就是可能命中我们要的答案,就让right = mid就好了。

那么这里有一个疑问,如果我们使用的参照物是A呢?

算法编写

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

这是参照物为D的情况,如果参照物是A的话:

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

如果参照物是A的情况,那么我们需要单独考虑数组是连续递增的情况,比如[1,2,3,4],如果参照物是A,也就是1,那么任意的数都会大于1,此时,left会一直++到4,最后返回的恰好是最大的而非最小的,那么这种情况,也就代表了数组没有经过旋转,所以直接返回nums[0]即可。


寻找缺失的数字

题目解析

题目要求非常简单,要求返回缺失的那个数字就可以了。

那这个题目虽然是简单难度,可是就非常有说法了。

什么说法呢?这道题可以有很多很多的解法。

比如我们可以直接遍历数组,如果前一个不等于后一个加一,就代表缺少了。

比如我们可以直接使用数学中的等差求和公式,减去整个数组的和就可以了。

比如我们可以使用位运算,利用^的特点,数^本身就是0,最后留下一个没有异或自己的数,从而找到。

比如我们可以利用哈希映射,将所有的值全部映射到一个数组里面,判断哪个数组的元素为0,也就可以返回对应的值了。

但是但是,以上的所有方法,四种方法都是O(N)的,并且哈希映射的方法还新开了一个空间,空间复杂度还是O(N)。就实际上来说都是比较慢的,我们可以利用二分查找来优化。

算法原理

算法原理,一问就是哪里去找二段性?

缺失的数字的左边,数组的元素都是等于数组的下标的,而缺失的数字的右边,数组的元素的下标都是不等于数组的元素的。而我们要的值是右边的左端点,所以left = mid + 1,right = mid,算法一下就明了了。

算法编写

class Solution 
{
public:
    int takeAttendance(vector<int>& records) 
    {
        int left = 0, 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;
    }
};

唯一需要注意的就是,如果数组是0 1 2 3 ,代表缺失的数字是4,所以此时不存在右边的区间,此时left和nums[left]相等的,所以需要left  + 1。

二分查找的部分题目就先到这里了。


感谢阅读!

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

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

相关文章

超越OpenAI GPT-4o,Yi-Lightning指南:中国AI大模型新巅峰

Yi-Lightning 是零一万物公司最新发布的旗舰模型&#xff0c;它在国际权威盲测榜单 LMSYS 上超越了硅谷知名 OpenAI GPT-4o-2024-05-13、Anthropic Claude 3.5 Sonnet&#xff0c;排名世界第六&#xff0c;中国第一&#xff0c;这标志着中国大模型首次实现超越 OpenAI GPT-4o 的…

InnoDB 存储引擎的底层逻辑架构白话-必知必会

目录标题 前言白话内存架构1. 自适应哈希索引自适应哈希索引的作用自适应哈希索引的工作原理自适应哈希索引与缓存的区别启用和禁用自适应哈希索引 2. Buffer pool3. Change buffer 下面我们就来详细分析一下&#xff0c;数据修改操作的步骤。4. Log Buffer 磁盘架构1. 系统表空…

一文了解AOSP是什么?

一文了解AOSP是什么&#xff1f; AOSP基本信息 基本定义 AOSP是Android Open Source Project的缩写&#xff0c;这是一个由Google维护的完全免费和开放的操作系统开发项目。它是Android系统的核心基础&#xff0c;提供了构建移动操作系统所需的基本组件。 主要特点 完全开源…

echarts散点图

一、类似散点图折线图不展示折线 option {grid: {left: 10,right: 20,top: 35,bottom: 15,containLabel: true},tooltip: {show: true,trigger: item,backgroundColor: "rgba(0,0,0,0)", // 提示框浮层的背景颜色。formatter: function (params) {var html <d…

基于Python的B站视频数据分析与可视化

基于Python的B站视频数据分析与可视化 爬取视频、UP主信息、视频评论 功能列表 关键词搜索指定帖子ID爬取指定UP主的主页爬取支持评论爬取生成评论词云图支持数据存在数据库支持可视化 部分效果演示 关键词搜索爬取 指定UP主的主页爬取 指定为黑马的了 爬取视频的时爬取评论…

基于大模型的Milvus向量数据库的背景与实战应用,计算与索引机制,Python代码实现

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下基于大模型的Milvus向量数据库的背景与实战应用&#xff0c;计算与索引机制&#xff0c;Python代码实现。本文详细介绍了milvus向量数据库的原理&#xff0c;并通过具体的数据样例和完整的Python代码实现&#xff0…

NodeJS连接MySQL 8.4报错:code: ‘ER_TABLEACCESS_DENIED_ERROR‘

NodeJS连接MySQL 8.4报错&#xff1a;code: ER_TABLEACCESS_DENIED_ERROR { code: ER_TABLEACCESS_DENIED_ERROR, errno: 1142, sqlMessage: "SELECT command denied to user 用户名localhost for table 表名", sqlState: 42000, index: 0, sql: SELECT …

SCR相对标准偏差、氨氮比、截面速度,多平面计算

SCR截面速度、氨氮比等标准及相对标准偏差计算。 程序用来处理fluent通过xyplot导出的数据&#xff0c;导出可以选择多个平面&#xff0c;可计算标准偏差SD、相对标准偏差RSD&#xff0c;平均速度,适用于求解多个平面 # -*- coding: utf-8 -*- """ Created on …

maven本地打jar包依赖

本地工程的pom文件中引入了mysql依赖&#xff0c;但是在maven库中没有拉下来&#xff0c;可以到mysql官网下载jar包&#xff0c;使用maven手动打包到本地仓库中&#xff1a; 官网地址&#xff1a;MySQL :: Download MySQL Connector/J (Archived Versions) 在jar包所在位置的路…

jupyter界面修改成中文教程

在系统变量里面增加一个变量名&#xff1a;LANG 变量值&#xff1a;zh_ CN.UTF8 成功修改成为中文

什么是JavaBean?

什么是JavaBean&#xff1f;—— Java开发中的数据封装利器 在Java开发中&#xff0c;JavaBean 是一个非常实用且常见的设计模式&#xff0c;它用于简洁、高效地封装和传递数据。随着Java应用的广泛使用&#xff0c;JavaBean成为许多开发者不可或缺的工具。在本文中&#xff0c…

【linux】centos7卸载默认的jdk

查看是否已经安装java java -version 查看java文件 rpm -qa | grep java 卸载相关包 rpm -e --nodeps java-1.8.0-openjdk-headless-1.8.0.262.b10-1.el7.x86_64rpm -e --nodeps python-javapackages-3.4.1-11.el7.noarchrpm -e --nodeps tzdata-java-2020a-1.el7.noarchrpm…

Labview通讯测试耗时

写法 写命令立即读出 写命令后立即读出&#xff0c;在同一时间不能有多个地方写入&#xff0c;因此需要在整个写入后读出过程加锁 项目中会存在多个循环并行执行该VI&#xff0c;轮询PLC指令 在锁内耗时&#xff0c;就是TCP读写的实际耗时为5-8ms&#xff0c;在主VI六个循环…

【面试经典150】day 7

目录 1.买卖股票的最佳时机 II 2.跳跃游戏 3.跳跃游戏 II 4.H 指数 5.O(1) 时间插入、删除和获取随机元素 6.除自身以外数组的乘积 7.加油站 8.分发糖果 1.买卖股票的最佳时机 II class Solution {public int maxProfit(int[] prices) {//和1相比&#xff0c;这个可以一直买…

【WebSocket实战】——创建项目初始架构

这一篇文章主要是为了介绍如何在visual中创建一个项目并服务于我们要做的websockt项目&#xff0c;所以这里如果已经懂得的人&#xff0c;可以直接跳过。 目录 1&#xff09;创建空白解决方案 2&#xff09;创建asp.NET Core项目 3&#xff09;创建winform项目作为客户端1 …

53页 PPT煤炭行业数字化转型规划方案

▲关注智慧方案文库&#xff0c;学习9000多份最新解决方案&#xff0c;其中 PPT、WORD超过7000多份 &#xff0c;覆盖智慧城市多数领域的深度知识社区&#xff0c;稳定更新4年&#xff0c;日积月累&#xff0c;更懂行业需求。 53页 PPT煤炭行业数字化转型规划方案 通过对煤企高…

乐维网管平台(一):如何精准掌控 IP 管理

业网络已成为支撑业务运转的关键基础设施&#xff0c;而在企业网络管理中&#xff0c;IP 管理至关重要&#xff0c;它就像是网络秩序的守护者&#xff0c;确保网络的高效运行、安全可靠。 一、为什么企业要进行 IP 管理 1. 优化资源分配 IP 地址作为网络中的重要资源&#xf…

驱动-----向内核新加文件

编译的过程是: 1.先复制一个默认的配置到.config(存放make menuconfig的配置结果)文件。 2.make menuconfig来可视化的选择编译的对象。 3.编译与否保存在.config里面 4.然后就makefile,使用.config中的配置 接下来就是加自己的驱动文件,把自己的文件编译加到内核里面…

探索 CSS Houdini:轻松构建酷炫的 3D 卡片翻转动画

在本文中&#xff0c;我将通过构建一个3D翻卡动画来探索Houdini的功能。这将帮助你了解Houdini的核心概念&#xff0c;并引导你完成实际的代码实现。你不仅能够掌握 Houdini 的核心概念&#xff0c;还可以跟随实际的代码实现&#xff0c;逐步完成这个动画效果。 我们将深入探讨…

SpringBoot基于若依项目工时统计成本核算管理源码带教程

是前后端分离的架构&#xff0c;前端使用Vue2&#xff0c;后端使用SpringBoot2。 技术框架&#xff1a;SpringBoot2.0.0 Mybatis1.3.2 Shiro swagger-ui jpa lombok Vue2 Mysql5.7 运行环境&#xff1a;jdk8 IntelliJ IDEA maven 宝塔面板 系统与功能介绍 这是一…