二分——力扣篇

news2025/7/19 19:11:30

二分——力扣篇

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

搜索旋转排序数组

在这里插入图片描述

在这里插入图片描述
定理一:只有在顺序区间内才可以通过区间两端的数值判断target是否在其中。

定理二:判断顺序区间还是乱序区间,只需要对比 left 和 right 是否是顺序对即可,left <= right,顺序区间,否则乱序区间。

通过不断的用Mid二分,根据定理二,将整个数组划分成顺序区间和乱序区间,然后利用定理一判断target是否在顺序区间,如果在顺序区间,下次循环就直接取顺序区间,如果不在,那么下次循环就取乱序区间。

  • 注意点一:整体二分前,必须对区间长度进行特判,比如二分之前,如果整个序列长度为1,按我这种二分方式l<r根本不可能进入二分。
  • 注意点二:判断是否为顺序区间,只需比较该区间左右端点的大小,错误想法是以为不会有重复的元素,所以只需要判断是否左下标对应的元素严格小于右下标对应的元素 ,其实不然,涉及区间必须对区间长度进行特判,比如二分之前,如果整个序列长度为1,按我这种二分方式l<r根本不可能进入二分。回到判断是否为顺序区间,如果区间长度为1或者2,l的值和mid的值是相等的,指向的自然是同一元素,会是相等的。例子为3 1 找 1。我又想,是不是在整个二分之前特判区间长度为2的情况就OK呢?不对,因为二分就是缩小区间范围的过程,并不一定开局就是target在仅有的两个元素之间,很有可能一直二分直到缩小到区间长度为2
    3、按照这套二分模板,
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}

不断缩小区间范围只能遵循一种规律那就是由int mid = l + r >> 1;决定的从小到大找和l = mid + 1; (一定是匹配出现的),或者是由int mid = l + r+1 >> 1;决定的从大到小找和l = mid ; 这里

if(target>=nums[mid]&&target<=nums[r]){
				if(nums[mid] == target) return mid;
      			else l=mid+1;	
}

如果此时不提前判断mid及时返回mid,那么l应当取的值是l=mid,显然不对(记住死循环解释) OK,提前判断mid,ac啦

class Solution {
public:
    int search(vector<int>& nums, int target) {
      int n=nums.size();
      if(n==0)return -1;
      if(n==1)return nums[0]==target?0:-1;
      int l=0,r=n-1;
      while(l<r){
      	int mid=(l+r)>>1;
//		if(nums[mid] == target) return mid;
//     数组旋转过后一定是一段或者两段上升的子段,仍然可以二分
//     但是整体二分[l,mid]不一定恰好处于上升子段之中,可能包含了俩子段各一部分
      	if(nums[l]<=nums[mid]){//不取等号是因为不存在重复元素 [l,mid]恰好处于升序子段
      		if(target>=nums[l]&&target<=nums[mid]){
      			r=mid;	
			}
			else l=mid+1;
		}
		else{//[l,mid]不完全处于升序子段,好办,[mid+1,r]一定属于
			if(target>=nums[mid]&&target<=nums[r]){
				if(nums[mid] == target) return mid;
      			else l=mid+1;	
			}
			else r=mid-1;
		}
	  }
      return (nums[l] == target)?l:-1;
    }
};

//3 1  
//1 
//-1 其实是1

另一种二分代码

class Solution {
public:
    int search(vector<int>& nums, int target) {
      int n=nums.size();
      if(n==0)return -1;
      if(n==1)return nums[0]==target?0:-1;
//      if(n==2){
//      	if(target==nums[0])return 0;
//      	else if(target==nums[1])return 1;
//      	else return -1;
//	  }
      int l=0,r=n-1;
      while(l<=r){
      	int mid=(l+r)>>1;
		if(nums[mid] == target) return mid;
//     数组旋转过后一定是一段或者两段上升的子段,仍然可以二分
//     但是整体二分[l,mid]不一定恰好处于上升子段之中,可能包含了俩子段各一部分
      	if(nums[l]<nums[mid]){//[l,mid]恰好处于升序子段
      	
      	//不取等号是因为不存在重复元素 ,错,要取, 比如 3 1 找1,l就是mid
//      	5 1 2 3 4找1,只要target找的范围缩小到了旋转点+左 或 右转点+左
      		if(target>=nums[l]&&target<nums[mid]){
      			r=mid-1;	
			}
			else l=mid+1;
		}
		else{//[l,mid]不完全处于升序子段,好办,[mid+1,r]一定属于
			if(target>nums[mid]&&target<=nums[r]){
      			l=mid+1;	
			}
			else r=mid-1;
		}
	  }
      return -1;
    }
};

搜索旋转排序数组II

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

10111 和 11101 这种。此种情况下 nums[start] == nums[mid],分不清到底是前面有序还是后面有序,此时 start++ 即可。相当于去掉一个重复的干扰项。

顺带发现,if(nums[mid] == target) return true;用我的二分模板,每次得到mid先判断也无伤大雅,提前发现提前返回而已,主要是注意缩小区间的方式

class Solution {
public:
    int search(vector<int>& nums, int target) {
      int n=nums.size();
      if(n==0)return -1;
      if(n==1)return nums[0]==target?true:false;
      int l=0,r=n-1;
      while(l<r){
      	int mid=(l+r)>>1;
		if(nums[mid] == target) return true;
 		if (nums[l] == nums[mid] && nums[mid] == nums[r]) {
                ++l;
                --r;
            }
      	else if(nums[l]<=nums[mid]){//不取等号是因为不存在重复元素 [l,mid]恰好处于升序子段
      		if(target>=nums[l]&&target<=nums[mid]){
      			r=mid;	
			}
			else l=mid+1;
		}
		else{//[l,mid]不完全处于升序子段,好办,[mid+1,r]一定属于
			if(target>=nums[mid]&&target<=nums[r]){
				if(nums[mid] == target) return true;
      			else l=mid+1;	
			}
			else r=mid-1;
		}
	  }
      return (nums[l] == target)?true:false;
    }
};

//3 1  
//1 
//-1 其实是1

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
三种情况主要就是mid落在的位置不同,需要使区间来到第二段

class Solution {
public:
    int findMin(vector<int>& nums) {
		int n=nums.size();
		int l=0,r=n-1;
		while(l<r){
			int mid=l+r>>1;
//经由 1 到 n 次 旋转,两段升序子序列,且第一段大于第二段,最小值一定在第二段
			if(nums[mid]<nums[r]){
//				l=mid;
				r=mid;
			}
			else{
//				r=mid-1;//不对的,记住永远在 第二段 找,lr需要使区间缩小到第二段
				l=mid+1;
			}
		}
		return nums[l];
    }
};

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    int findMin(vector<int>& nums) {
		int n=nums.size();
		int l=0,r=n-1;
		while(l<r){
			int mid=l+r>>1;
//经由 1 到 n 次 旋转,两段升序子序列,且第一段大于第二段,最小值一定在第二段
			if(nums[mid]<nums[r]){
//				l=mid;
				r=mid;
			}
			else if(nums[mid]>nums[r]){
//				r=mid-1;//不对的,记住永远在 第二段 找,lr需要使区间缩小到第二段
				l=mid+1;
			}
			else {//if(nums[mid]==nums[r])
				r--;
			}
		}
		return nums[l];
    }
};

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

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

相关文章

案例学习20之内存长期占用导致系统缓慢

前言&#xff1a; 发现问题&#xff0c;解决问题&#xff0c;是贯穿整个项目开发过程的事情&#xff0c;能够处理更多的问题&#xff0c;随着经验的丰富&#xff0c;提前预知更多的问题&#xff0c;让问题不出现是最好的解决问题方式。 问题背景&#xff1a; 项目运行过程中出现…

基于redis实现点赞数,点击数,排行榜

使用场景 对于某些视频或者文章有点赞数和点击数, 通过这些数据就可以进行排行榜的功能了 使用异步队列 redis的集合 A.php //点击数 $redis->zIncrBy(click.:.date(Ymd),1,$videoId); //点赞数 $redis->zIncrBy(love.:.$videoId,1,$$user); //获取当前video的播放数…

PMP项目管理项目范围管理

目录1 项目范围管理概述2 规划范围管理3 收集需求4 定义范围5 创建 WBS6 确认范围7 控制范围1 项目范围管理概述 项目范围管理包括确保项目做且只做所需的全部工作&#xff0c;以成功完成项目的各 个过程。管理项目范围主要在于定义和控制哪些工作应在项目内&#xff0c;哪些工…

界面原型设计

引用锤子科技视觉设计总监——罗子雄在重庆TEDx活动上说的一小段话: 每当我们看到一些美妙的设计的时候,很多人心里面会有一种冲动,这种冲动会让你们想去创造一些新的东西,创造一些美妙的事物。 我们常说用户体验用户体验,用户使用你的软件,第一个会接触的是什么?没错,…

读WiscKey: Separating Keys from Values in SSD-conscious Storage

在我看来本论文的主要贡献在于相对减轻了传统LSM compact所带来的写放大问题。其核心设计在于使key、value分离以及gc只保持有效数据 key、value分离 作者对于key、value分离策略的观察主要来自于排序是以往LSM性能消耗最大的地方&#xff0c;但是真正影响排序的与占用大储存…

推荐五款宝藏软件,身为宝藏男孩和宝藏女孩的你,不试一下吗?

今天带来五款宝藏软件&#xff0c;身为宝藏男孩和宝藏女孩的你们&#xff0c;不试一下吗&#xff1f; 1.EPUB阅读器——Starrea Starrea 是一款Windows平台的EPUB电子书阅读器&#xff0c;它虽然只支持一个平台&#xff0c;但是提供了很多额外的功能&#xff0c;其中包括 文…

Java之线程总结一

Java之线程总结一 线程实现方式 官方文档说的是实现线程的方式有两种&#xff1b;本质上只有一种&#xff0c;就是构造Thread类&#xff0c;而实现线程执行单元的方式有两种&#xff1a; 继承Thread类&#xff0c;重写run方法&#xff1b;实现Runnable接口的run方法&#xf…

RHEL8.5解决libgdiplus绘图问题

最近有客户服务器使用RHEL8.5了。由于之前测试和编译的dotnetcore在Linux下绘图包libgdiplus都是在centos7.6编译的。把CentOS7.6编译的二进制程序之前试CentOS7.9使用没问题&#xff0c;然后RHEL8.5无法正常绘图。由于之前搞统信那些系统发现了包得在对应系统源码编译才行。所…

Java web基于SSM的停车场管理系统的设计与实现

1&#xff0c;项目介绍 Java web基于SSM的停车场管理系统拥有三种角色&#xff0c;分别为用户&#xff0c;管理员&#xff0c;超级管理员。 停车位管理&#xff08;管理员&#xff0c;超级管理员&#xff09;停车卡管理&#xff08;用户&#xff0c;管理员&#xff0c;超级管…

Vue3视频播放器组件Vue3-video-play入门教程

Vue3-video-play适用于 Vue3 的 hls.js 播放器组件 | 并且支持MP4/WebM/Ogg格式。 1、支持快捷键操作 2、支持倍速播放设置 3、支持镜像画面设置 4、支持关灯模式设置 5、支持画中画模式播放 6、支持全屏/网页全屏播放 7、支持从固定时间开始播放 8、支持移动端&#xff0c;移动…

pyqt5环境搭建

1、打开Terminal ,用命令pip install pyqt5-tools 或者 pip install pyqt5-tools -i https://pypi.tuna.tsinghua.edu.cn/simple安装PyQt5安装成功后就可看到PyQt5版本2、同上方法&#xff0c;继续安装pyqt5-tools扩展工具&#xff0c;里面包括了QtDesigner等很好用的工具。3、…

二进制哈希码快速搜索:Multi-Index Hashing

前言 如果你对这篇文章感兴趣&#xff0c;可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」&#xff0c;查看完整博客分类与对应链接。 哈希方法通常包含两个部分&#xff1a; 【编码】将元素通过「data-dependent」或「data-independent」的方式映射为二进制…

C变量区域

C语言中有五大内存分区&#xff0c;分别是栈区、堆区、全局区/静态区、常量区和代码区。1.栈区&#xff1a;由编译器自动分配释放&#xff0c;存放函数的参数值、局部变量的值等。当调用函数的时候函数中定义的变量会被加到栈中&#xff0c;当函数离开的时候&#xff0c;被添加…

HTML看这一篇就够啦,HTML基础大全,可用于快速回顾知识,面试首选

HTML 1 基础 1.1 DOCTYPE <!DOCTYPE> 文档类型声明&#xff0c;作用就是告诉浏览器使用哪种HTML版本来显示网页。 <!DOCTYPE html> 这句代码的意思是: 当前页面采取的是 HTML5 版本来显示网页. 注意: 声明位于文档中的最前面的位置&#xff0c;处于 标签之前。 …

互联网新理念,对于WEB 3.0 你怎么看?

WEB 3.0 这个名词走进大众视野已经有一段时间了&#xff0c;也曾在各个圈子里火热一时&#xff0c;至今各大互联网企业任旧在 WEB 3.0 上不断探索。但关于 WEB 3.0 是什么这个问题&#xff0c;其实大部分人都没有一个比较明确的认知&#xff0c;包括区块链和元宇宙等相关行业的…

【设计模式】备忘录模式和迭代器模式

备忘录模式和迭代器模式备忘录模式代码示例迭代器模式代码示例使用迭代器遍历集合的同时不能删除/增加元素总结备忘录模式 备忘录模式&#xff0c;也叫快照&#xff08;Snapshot&#xff09;模式。 在 GoF的《设计模式》⼀书中&#xff0c;备忘录模式是这么定义的&#xff1a;…

【Spring6】面向切面:AOP

5.1、场景模拟 搭建子模块&#xff1a;spring6-aop 5.1.1、声明接口 声明计算器接口Calculator&#xff0c;包含加减乘除的抽象方法 public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j);}5.1.2、创建…

计算机视觉与深度学习 | Visual ChatGPT:微软开源视觉(图文)聊天系统——图像生成、迁移学习、边缘检测、颜色渲染等多功能(附代码下载链接)

===================================================== github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 ===================================================== Visual ChatGPT: Talking, Drawing and Editing with V

LeetCode 134. 加油站(函数图像法 / 贪心)

题目&#xff1a; 链接&#xff1a;LeetCode 134. 加油站 难度&#xff1a;中等 在一条环路上有 n 个加油站&#xff0c;其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车&#xff0c;从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中…

CentOS系统变化看开源演进

CentOS社区还存不存在&#xff1f;CentOS项目还存不存在&#xff1f;众多CentOS用户将何去何从&#xff1f;伴随CentOS停更&#xff0c;大家可能会有这样那样的疑问&#xff0c;今天针对以上问题&#xff0c;我来进行一一解答。CentOS实际上有两个变种&#xff0c;一个叫做Cent…