【旋转数组】二分法专题

news2024/10/9 10:46:40

这两天看这个看晕乎了...痛定思痛,必须学会!

  • 讲解
    • 寻找旋转排序数组中的最小值
    • 寻找旋转排序数组中的最小值II
  • 小总结
    • 搜索选择排序数组
    • 搜索旋转排序数组II
  • 小总结

讲解

左闭右闭:
left = 0, right = nums.size() - 1
找target
进入while循环,while(),闭区间[1, 1]合法吗?合法,那么
while(left <= right)
mid = (left + right) / 2
if(mid > target) right = mid - 1;//不用=,因为mid一定不是
else if(mid < target) left = mid + 1;
else return mid
跳出while循环之后,return -1

左闭右开:
left = 0,right = nums.size()
[1,1)合法吗?不合法!所以while(left < right),不可以等于
mid = (left + right) / 2
if(mid > target) right = mid
else if(mid < target) left = mid + 1;
else return mid
跳出while,return -1

左开右开:
left = 0, right = nums.size()
while(left + 1 != right)
mid = (left + right) / 2;
if(mid > target) right = mid
else left = mid;
跳出while,return right

()是最容易的写法

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

无重复元素,所有元素都不一样

在这里插入图片描述
旋转数组这一系列题有一点非常怪,tmd,那就是12345不可能旋转成54321,所以开区间那边都是nums.size() - 1

二分法需要保证的不是连续性,而是二段性质,简单点来说,就是这序列的数组有没有一个明显的界限分成两部分,这个题显然有,那么直接套模板是可以的,只是在修改left和right的时候需要注意

咱要找的是最小值,最小值在哪一段?右边那一段,所以我们选择nums.back()作为比较点,接下来,以开区间作为咱的写法,left = -1, right = nums.size() - 1,这里right为什么这么写上面已经提过了

if(nums[mid] < nums.back()),说明咱们要找的最小值的点还在更左边,那么right = mid
else left = mid;

最后仍然return nums[right]

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

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

有重复元素~!

普通的二分法也只是要求数组有序而没有说必须无重复,但是在旋转数组中,咱们如果有重复数组的话会麻烦很多,主要体现在二段性的缺失。
举一个缺失二段线的例子:
在这里插入图片描述
由于在旋转点有元素重复,所以左边大于等于2,邮编小于等于2,都有等于2的元素,导致没办法分成特点鲜明的两端,那么怎么做呢?把二段性补回来即可

怎么补?也不简单,首先这个题很变态,12345是有效用例,54321就是无效的
所以假设哈,假设

开头和结尾出现了重复数,比如[5,6,7,1,2,3,4,5,5],第一段大于等于5,第二段小于等于5,这种情况right–和left++,将5去除,尚能解决,由于我说过了12345在这里是有效用例,54321就不是,所以我们选择right–

class Solution {
public:
    int findMin(vector<int>& nums) {
        // 恢复二段性
        int n = nums.size();
        int left = -1, right = n - 1;
        while(left < right && nums[right] == nums[0]){
            right--;
        }
        int flag = right;
        // 找到旋转点
        while (left + 1 < right){
            int mid = (left + right) / 2;
            if(nums[mid] < nums[flag]){
                right = mid;
            } 
            else{
                left = mid;
            }
        }
        return right == -1 ? nums[0] : nums[right];
    }
};

在这里插入图片描述
以上right–可以解决头尾重复,但无法解决12334这种情况
为什么呢?
首先这种情况不在头尾重复缺失二段性的例子里面,当与back比较的时候,如果相等,按照上面的代码我们会使left = mid,但是最小值显然在左边,我们要改的是right才对

class Solution {
public:
    int findMin(vector<int>& nums) {
        // 恢复二段性
        int n = nums.size();
        int left = -1, right = n - 1;
        while(left < right && nums[right] == nums[0]){
            right--;
        }
        int flag = right;
        // 找到旋转点
        while (left + 1 < right){
            int mid = (left + right) / 2;
            if(nums[mid] <= nums[flag]){
                right = mid;
            } 
            else{
                left = mid;
            }
        }
        return right == -1 ? nums[0] : nums[right];
    }
};

小总结

以上两道题我小总结一下,有无重复元素影响的是=加不加,其实第一题也可以加,在无重复元素的时候,开区间加不加其实没所谓,但是当有重复元素的时候,考虑这个很重要

我在刚开始学习二分法的时候,背诵的模板的不加等号的if,改的是left,其实我如果照着这个模板写这两道题,就不会错,但是我鬼使神差把不加等号那边改right了,导致一直不过

那么可以总结一个有无重复元素通用的模板

针对第一题,第二题是一样的:

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

搜索选择排序数组

无重复元素,找target下标

先找最小值,然后和最小值比较,往哪边找
开区间改left是好习惯!

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

    }
};

搜索旋转排序数组II

有重复元素,找target下标

哎呀,这题就好难了

如果按照之前的做法,会败在用例[2,2,2,3,2,2,2]
为什么呢?

因为后面的2在一开始就被right–掉了,剩下前面一节2和3,这时候返回的最小值一定是第一个2,即index = 0,要找的是3,-1和index之间哪里有3呢?

理想情况,我们要找的最小值应该是[2,2,2,3,2,2,2]中间标黄的2

md这就是这一系列题很恶心的地方,写的烦死了

之后我想到一个完美的解决方案过这个用例,那就是,两边都return一下,只要有true就是true,都是false才是false,完美!
更改的关键代码:

if(!lower_bound(nums, -1, index, target)){
  return lower_bound(nums, index - 1, flag, target);
}
else return true;  

新的问题来了,right–后相当于后面一节相似的不要了,假如数组是22222的话,right会一直减,直到为-1,那么flag也会是-1,之后right可以在return部分纠正为0,但flag还会是-1,所以这里的flag需要纠正:

flag = right;
if(right == -1) flag = 0;

总代码:

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

小总结

说实话,我感觉自己在面向用例编程,最后的代码并不优美,但也是我自己一点点想出来的,也更加熟悉了二分法,每道题都比前面的题目多一点点特殊情况,很头疼,我在想,这种题目考我的话,思考还不如背诵,思考我还需要用例,但是换个环境哪有用例?找别人优美的代码学一学,背一背,可能比自己孤军奋战折腾出来更好,最后附上自己的提交记录,因为真的不容易。。
在这里插入图片描述

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

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

相关文章

低质量数据的多模态融合方法

目录 多模态融合 低质量多模态融合的核心挑战 噪声多模态数据学习 缺失模态插补 平衡多模态融合 动态多模态融合 启发式动态融合 基于注意力的动态融合 不确定性感知动态融合 论文 多模态融合 多模态融合侧重于整合多种模态的信息,以实现更准确的预测,在自动驾驶、…

LeetCode 73 Set Matrix Zeroes 题目解析和python代码

题目&#xff1a; Given an m x n integer matrix matrix, if an element is 0, set its entire row and column to 0’s. You must do it in place. Example 1: Input: matrix [[1,1,1],[1,0,1],[1,1,1]] Output: [[1,0,1],[0,0,0],[1,0,1]] Example 2: Input: matrix …

银河麒麟服务器:检查仓库源连接状态

银河麒麟服务器&#xff1a;检查仓库源连接状态 1. 清理YUM缓存2. 生成YUM缓存 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在银河麒麟高级服务器操作系统中&#xff0c;要检查仓库源是否连接成功&#xff0c;可以执行以下两个命令&…

探针台的应用领域

探针台&#xff08;Probe Station&#xff09;是一种用于对半导体器件进行电性能测试的重要设备。它通常由精密的机械结构、高性能的探针针头和电性能测试仪器组成。探针台可以对半导体芯片、集成电路和其他微电子器件进行直接的电性能测试&#xff0c;从而为研究和生产提供有价…

【华为HCIP实战课程八】OSPF网络类型及报文类型详解,网络工程师

一、点到点网络类型 1、两台路由器 2、支持广播、组播 P2P(PPP、HDLC、帧中继子接口) 我们需要三个维度考虑 A、是否自动通过组播发现邻居 B、时间(Hello和Dead) C、DR和BDR----多点接入网络需要用到(广播和NBMA) 点到点是组播自动发现邻居,Hello 10S,Dead 40S…

新一代文件传输革命:探索超越传统FTP的替代方案

为什么要进行FTP替代&#xff1f; FTP是一种应用特别广泛的文件传输协议&#xff0c;可以实现文件的上传、下载和其他文件操作&#xff0c;因其简单易用、广泛支持、兼容性好、成本低廉的特性&#xff0c;在全球各国都流行了多年&#xff0c;并且延续至今&#xff0c;还有很多…

命令行py脚本——Linux下方便快捷地运行*.py脚本

命令行参数传递&#xff0c;shell批指令和命令别名。 (笔记模板由python脚本于2024年10月08日 12:25:54创建&#xff0c;本篇笔记适合喜欢python和Linux的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣…

Index-1.9B模型部署教程

一、介绍 Index-1.9B 系列是 Index 系列型号的轻量级版本&#xff0c;包含以下型号&#xff1a; Index-1.9B 基础&#xff1a;具有 19 亿个非嵌入参数的基础模型&#xff0c;在 2.8T 主要为中文和英文的语料上进行预训练&#xff0c;在多个评测基准上与同级别模型相比领先。I…

华为OD机试 - 人数最多的站点(Java 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;E卷D卷A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加…

知识付费市场的前景 集师小程序 集师知识付费服务 集师知识付费体系

在数字化时代的2020年代中&#xff0c;知识付费市场如同一颗璀璨的新星&#xff0c;正在迅速崛起并改变着人们的学习方式和消费习惯。这一市场的繁荣&#xff0c;不仅得益于互联网技术的飞速发展&#xff0c;更源于人们对高质量、个性化知识内容的强烈需求。 以前知识付费从最初…

MySQL从主库恢复从库

主库备份数据&#xff0c;拷贝至从节点 1.1 备份数据 sudo python /data/apps/xtrabackup/script/xtrabackup.py -m full 备份目录为&#xff1a; /data/mysql_bakcup/<port>/<date>/full_<date> 例&#xff1a;/data/mysql_backup/13306/20231124/full_1640…

Kubernetes(K8s)部署

主机名ip角色docker-harbor.revkarl.org172.25.254.250harbor仓库k8s-master172.25.254.100master&#xff0c;k8s集群控制节点k8s-node1172.25.254.10worker&#xff0c;k8s集群工作节点k8s-node2172.25.254.20worker&#xff0c;k8s集群工作节点 注意&#xff1a; 所有节点禁…

【答疑解惑】图文深入详解undo和redo的区别及其底层逻辑

题记&#xff1a;最近有些人问我&#xff0c;undo和redo到底是什么关系&#xff0c;他们中不乏已经入行3-4年的同学&#xff0c;今天咱们就来深入探讨下到底什么是undo和redo&#xff0c;他们分别做什么&#xff0c;底层逻辑原理是什么等等。 1. undo 1.1 undo的存储结构 Un…

通信工程学习:什么是RFID射频识别

RFID&#xff1a;射频识别 RFID射频识别&#xff08;Radio Frequency Identification&#xff09;&#xff0c;又称为无线射频识别&#xff0c;是一种非接触式的自动识别技术。它通过无线电信号来识别特定目标并读写相关数据&#xff0c;而无需在识别系统与特定目标之间建立机械…

亳州自闭症寄宿制学校,关注孩子的学习和生活

在特殊教育领域&#xff0c;自闭症儿童的教育与成长一直是社会各界关注的焦点。近年来&#xff0c;随着对自闭症认识的加深&#xff0c;越来越多的寄宿制学校应运而生&#xff0c;致力于为这些特殊的孩子提供全面、个性化的教育服务。在安徽亳州&#xff0c;这样的学校正努力为…

大数据毕业设计选题推荐-国产电影数据分析-Python数据可视化-Hive-Hadoop-Spark

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

各省常住人口及人口密度面板数据(2000-2022年)

常住人口指在某地区居住超过一定时间&#xff08;通常为半年以上&#xff09;的人口&#xff0c;而人口密度则指每平方千米或每公顷内的常住人口数。数据集的主要指标包括&#xff1a; 省份年份常住人口&#xff08;万人&#xff09;人口密度&#xff08;人/平方公里&#xff…

荣誉|奇点云入选“2024年成长型浙江数商”名单

近期&#xff0c;浙江省经济和信息化厅根据《关于推进浙江数商高质量发展的实施意见》&#xff08;浙制高办〔2024〕21号&#xff09;&#xff0c;在全省范围内遴选在全国具有影响力的10家“领军型浙江数商”企业&#xff0c;以及50家在细分领域有影响力的“成长型浙江数商”企…

GBC律所老牌代理Tory Burch 汤丽柏琦再次维权

案件基本情况起诉时间&#xff1a;2024-9-17案件号&#xff1a;24-cv-08553品牌&#xff1a;Tory Burch原告&#xff1a;River Light v, L.P.原告律所&#xff1a;GBC起诉地&#xff1a;伊利诺伊州北部法院品牌介绍Tory Burch汤丽柏琦是美国奢华时尚生活方式品牌&#xff0c;以…

26.删除有序数组中的重复项

题目::26. 删除有序数组中的重复项 - 力扣&#xff08;LeetCode&#xff09; 思路:只要不和前面的数一样就可以移动指针&#xff0c;进行赋值 代码: class Solution { public:int removeDuplicates(vector<int>& nums) {int slow 0 ;for(int fast 1; fast < …