二分查找习题篇(下)

二分查找习题篇(下)

1.山脉数组的峰顶索引

题目描述:

给定一个长度为 n 的整数 山脉 数组 arr ,其中的值递增到一个 峰值元素 然后递减。

返回峰值元素的下标。

你必须设计并实现时间复杂度为 O(log(n)) 的解决方案。

示例 1:

输入:arr = [0,1,0]
输出:1

示例 2:

输入:arr = [0,2,1,0]
输出:1

示例 3:

输入:arr = [0,10,5,2]
输出:1

解法一:暴力枚举 O(N)

算法思路:

根据峰顶值的特点(比两侧元素都要大),遍历数组内的每一个元素,找到一个比左右两边元素都大的元素即可。

代码实现:
class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr) 
    {
        int n = arr.size();
        // 遍历数组内每⼀个元素,直到找到峰顶
        for (int i = 1; i < n - 1; i++) 
            // 峰顶满⾜的条件
            if (arr[i] > arr[i - 1] && arr[i] > arr[i + 1])
            	return i; 
        // 为了处理 oj 需要控制所有路径都有返回值
        return -1;
    }
};

解法二:二分查找算法

算法思路:

由题意我们可以将数组分为两部分,以峰顶值元素i为界,i左边区域是arr[i]>arr[i-1],i右边区域是arr[i]<arr[i-1]。即具有“二段性”,可以用二分查找。

算法流程:

1.令left=0,right=arr.size()-1;

2.当left<right时,下列一直循环:

找到待查找区间的中间点 mid ,找到之后分两种情况讨论:

  • arr[mid]>arr[mid-1],说明mid处于i的左边区域,更新left=mid;
  • arr[mid]<arr[mid-1],说明mid处于i的右边区域,更新right=mid-1.
代码实现:
class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr)
     {
        int left=0,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;
    }
};

2.寻找峰值

题目描述:

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。

你可以假设 nums[-1] = nums[n] = -∞

你必须实现时间复杂度为 O(log n) 的算法来解决此问题。

示例 1:

输入:nums = [1,2,3,1]
输出:2
解释:3 是峰值元素,你的函数应该返回其索引 2。

示例 2:

输入:nums = [1,2,1,3,5,6,4]
输出:1 或 5 
解释:你的函数可以返回索引 1,其峰值元素为 2;
     或者返回索引5, 其峰值元素为 6。

算法思路:

看题,我们可以直到这道题和上一道题很像;区别在于在上一题中,所给的数组是一个山脉数组,而这道题是无序的。

由题意我们可以将数组分为两部分,以峰顶值元素i为界。

  1. nums[i]>nums[i+1]时,在[i,i+1]呈现一个下降的趋势。而nums[-1]=-∞,所以,i的左边区域一定会有一个峰顶值;而nums[n] = -∞,所以,i的右边区域不一定存在峰顶值。
  2. nums[i]<nums[i+1]时,在[i,i+1]呈现一个上升的趋势。我们同理可以确定,i的左边区间不一定存在峰顶值,但i的右边区间一定会存在一个峰顶值。

由此可见,数组具有“二段性”,可以用二分查找。

算法流程:

1.令left=0,right=nums.size()-1;

2.当left<right时,下列一直循环:

找到待查找区间的中间点 mid ,找到之后分两种情况讨论:

  • nums[mid]>nums[mid+1],此时mid处于i的左边区域,左区域一定会存在山峰,更新right=mid,在左区域去寻找结果;
  • nums[mid]<nums[mid+1],此时mid处于i的右边区域,右区域一定会存在山峰,更新left=mid+1,在右区间去寻找结果。

代码实现:

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

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

题目描述:

已知一个长度为 n 的数组,预先按照升序排列,经由 1n旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:

  • 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
  • 若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]

注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]]

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

输入:nums = [3,4,5,1,2]
输出:1
解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。

示例 2:

输入:nums = [4,5,6,7,0,1,2]
输出:0
解释:原数组为 [0,1,2,4,5,6,7] ,旋转 3 次得到输入数组。

示例 3:

输入:nums = [11,13,15,17]
输出:11
解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。

解法一:暴力查找最小值 O(N)

解法二:二分查找算法

算法思路:

二分的本质:找到一个判断标准,使得查找区间能够一分为二。

题目中的数组的规律如下:

在这里插入图片描述

通过观察,可以知道输入数组nums具有“二段性”,所以可以用二分查找算法解题

在这幅图中,C点即数组中我们所求的最小元素。

[A~B] : nums[i]>nums[n-1];

[C~D] : nums[i]<=nums[n-1].

算法流程:
  1. left =0, rightright=nums.size()-1;

  2. left<right时,下列一直循环:

    找到待查找区间的中间点 mid ,找到之后分三种情况讨论:

  • [A,B] 中,满足nums[mid]>nums[n-1],下次循环时需要更新left=mid+1;

  • [C,D] 中,满足nums[mid]<=nums[n-1],下次循环时需要更新right=mid;

  1. left=right,区间长度变成1,这时就是我们要找的结果。
代码实现:
class Solution {
public:
    int findMin(vector<int>& nums) 
    {
        int left=0,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];      
    }
};

4.0〜n-1中缺失的数字

题目描述:

一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0〜n-1之内。在范围0〜n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。

示例 1:

​ 输入: [0,1,3]

​ 输出: 2

示例 2:

​ 输入: [0,1,2,3,4,5,6,7,9]

​ 输出: 8

限制:

​ 1 <= 数组长度 <= 10000

算法思路:

本题有多种时间复杂度为O(N)的解法:

  • 哈希表
  • 直接遍历找结果
  • 位运算
  • 数学(高斯求和公式)

算法优化:

在这个升序的数组中,我们发现:

  • 在缺失位置的左边,数组内的元素都是与数组的下标相等的;

  • 在缺失位置的右边,数组内的元素与数组下标是不相等的。

因此,本题数组具有“二段性”,可以用二分查找算法解题。

算法流程:

1.令left=0,right=nums.size()-1;

2.当left<right时,下列一直循环:

找到待查找区间的中间点 mid ,找到之后分两种情况讨论:

  • mid在缺失位左边:nums[mid]==mid,更新left=mid+1;

  • mid在缺失位右边:nums[mid]!=mid,更新right=mid.

  1. 细节处理:要是循环完,没有缺失的元素,那么缺失的就是最后一个元素

代码实现:

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 records[left]==left?left+1:left;
    }
};

在这里,二分查找算法在这告一段落,后续会给友友们带来更多的算法解题,感觉不错的友友们可以一键三连支持一下笔者,有任何问题欢迎在评论区留言哦~

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

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

相关文章

Linux学习笔记之shell快速入门及相关变量

Shell是什么 Shell是一个命令解释器&#xff0c;它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序&#xff0c;用户可以通过Shell来启动、挂起甚至编写一些程序。 Shell脚本执行方式 脚本格式要求 脚本以#!/bin/bash开头脚本需要有可执行权限 脚本的常…

el-table 行列文字悬浮超出屏幕宽度不换行的问题

修改前的效果 修改后的效果 ui框架 element-plus 在网上找了很多例子都没找到合适的 然后这个东西鼠标挪走就不显示 控制台也不好调试 看了一下El-table的源码 他这个悬浮文字用的el-prpper 包着的 所以直接改 .el-table .el-propper 设置为max-width:1000px 就可以了 吐槽一…

ApiSmart x Qwen2.5-Coder 开源旗舰编程模型媲美 GPT-4o, ApiSmart 实测!

通义千问代码模型开源版。Qwen2.5-Coder相比CodeQwen1.5有了实质性的改进。Qwen2.5-Coder在包含5.5万亿Token的编程相关数据上进行了训练&#xff0c;使即使较小的编程专用模型也能在编程评估基准测试中表现出媲美大型语言模型的竞争力。 阿里云-2024年11月12日 Qwen2.5-Coder …

Java项目实战II基于微信小程序的个人行政复议在线预约系统微信小程序(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 基于微信小…

MyBatis xml 文件中 SQL 语句的小于号未转义导致报错

问题现象 在 MyBatis 的 xml 文件中添加了一个 SQL 语句 <select id"countXxx" resultType"int">select count(*) from t1 where count < 3 </select>启动 Spring Boot 应用程序后报错&#xff1a; Caused by: org.apache.ibatis.builde…

C++20 STL CookBook 7 Containers(II)

让vector在插入删除的时候仍然保证是有序的 首先&#xff0c;STL的确提供了一种办法来检查我们的目标容器是不是有序的&#xff1a;std::is_sorted - cppreference.com&#xff0c;也就是std::is_sorted。我们当然可以这样做&#xff1a; #include <iostream> #include…

FlinkSql读取kafka数据流的方法(scala)

我的scala版本为2.12 <scala.binary.version>2.12</scala.binary.version> 我的Flink版本为1.13.6 <flink.version>1.13.6</flink.version> FlinkSql读取kafka数据流需要如下依赖&#xff1a; <dependency><groupId>org.apache.flink&…

语音 AI 革命:未来,消费者更可能倾向于与 AI 沟通,而非人工客服

「未来&#xff0c;消费者更可能倾向于与 AI 沟通&#xff0c;而非人工客服&#xff0c;因为这将成为解决问题的最高效途径。」 这篇来自 Bessemer Venture Partners 的报告&#xff0c;是目前为止对语音 AI 在企业应用上最完整清晰的一次梳理。 核心要点&#xff1a; 尽管市…

【t365】基于springboot的高校疫情防控系统

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对信息管理混乱&#xff0c;出错率高&#xff0c;信息安全性差&#x…

DAY27|贪心算法Part01|LeetCode:455.分发饼干、376. 摆动序列、53. 最大子序和

贪心算法 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 贪心算法并没有固定的套路&#xff0c;最难想的就在于如何通过局部最优去推出全局最优。在做一个题目的时候&#xff0c;靠自己手动模拟&#xff0c;如果模拟可行&#xff0c;就可以试一试贪心策略…

四万字长文SpringBoot、Spring、SpringMVC等相关面试题(注:该篇博客将会持续维护 最新维护时间:2024年11月12日)

&#x1f9f8;本篇博客重在讲解SpringBoot、Spring、SpringMVC等相关面试题&#xff0c;将会实时更新&#xff0c;欢迎大家添加作者文末联系方式交流 &#x1f4dc;JAVA面试题专栏&#xff1a;JAVA崭新面试题——2024版_dream_ready的博客-CSDN博客 &#x1f4dc;作者首页&…

免费HTML模板和CSS样式网站汇总

HTML模板&#xff1a;&#xff08;注意版权&#xff0c;部分不可商用&#xff09; 1、Tooplate&#xff0c;免费HTML模板下载 Download 60 Free HTML Templates for your websitesDownload 60 free HTML website templates or responsive Bootstrap templates instantly from T…

深入理解接口测试:实用指南与最佳实践5.0(二)

✨博客主页&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客内容》&#xff1a;.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 &#x1f4e2;博客专栏&#xff1a; https://blog.csdn.net/m0_63815035/cat…

SpringBoot技术:共享汽车行业的新动力

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了共享汽车管理系统的开发全过程。通过分析共享汽车管理系统管理的不足&#xff0c;创建了一个计算机管理共享汽车管理系统的方案。文章介绍了共享汽车管理系统的系…

Java Review - 线程池原理源码解析

文章目录 Pre为什么要用线程池线程池的优点&#xff08;1&#xff09;重复利用线程&#xff08;2&#xff09;控制线程的数量 线程池实现原理线程池ThreadPoolExecutor类关系线程池的工作流程任务队列空闲线程的存活时间参数ThreadFactory拒绝策略被拒绝后的任务如何再次执行 向…

昇思大模型平台打卡体验活动:项目4基于MindSpore实现Roberta模型Prompt Tuning

基于MindNLP的Roberta模型Prompt Tuning 本文档介绍了如何基于MindNLP进行Roberta模型的Prompt Tuning&#xff0c;主要用于GLUE基准数据集的微调。本文提供了完整的代码示例以及详细的步骤说明&#xff0c;便于理解和复现实验。 环境配置 在运行此代码前&#xff0c;请确保…

【MySQL】数据库表连接简明解释

未经许可,不得转载。 文章目录 表连接表连接的类型内连接与外连接结合 WHERE 条件交叉连接(cross join)表连接 在关系型数据库中,建模是数据组织的核心难点。数据库建模需要将数据关系理清,构建出适合存储和查询的结构。 所谓“模型”包括实体(entity) 和关系(relati…

离线安装GDAL与MapServer:在银河麒麟V10上的快速指南

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 ✨特色专栏&#xff1a…

17.UE5丰富怪物、结构体、数据表、构造函数

2-19 丰富怪物&#xff0c;结构体、数据表格、构造函数_哔哩哔哩_bilibili 目录 1.结构体和数据表格 2.在构造函数中初始化怪物 3.实现怪物是否游荡 1.结构体和数据表格 创建蓝图&#xff1a;结构体蓝图 在结构体蓝图中添加变量&#xff0c;如下所示&#xff0c;为了实现不…

Kafka 快速入门(一)

1.1安装部署 1.1.1 集群规划 bigdata01bigdata02bigdata03zookeeperzookeeperzookeeperkafkakafkakafka 1.1.2 集群部署 官方下载地址&#xff1a;http://kafka.apache.org/downloads.html 检查三台虚拟机的zk是否启动&#xff1a;zkServer.sh start 默认启动方式 1)解压…