【寻找one piece的算法之路】——双指针算法!他与她是否会相遇呢?

💐个人主页:初晴~

📚相关专栏:寻找one piece的刷题之路


什么是双指针算法 

双指针算法是一种常用的编程技巧,尤其在处理数组字符串问题时非常有效。这种方法的核心思想是使用两个指针遍历数据结构,这两个指针通常分别位于数据结构的起始位置或某些特定位置,通过移动这两个指针来达到解决问题的目的。双指针算法可以显著减少时间复杂度,使其从O(n2)O(n2)降低到O(n)O(n),甚至在某些情况下可以达到O(log⁡n)O(logn)。

常⻅的双指针有两种形式,⼀种是对撞指针,⼀种是左右指针
对撞指针:⼀般⽤于顺序结构中,也称左右指针。
  • 对撞指针从两端向中间移动。⼀个指针从最左端开始,另⼀个从最右端开始,然后逐渐往中间逼近。
  • 对撞指针的终⽌条件⼀般是两个指针相遇或者错开(也可能在循环内部找到结果直接跳出循 环),也就是:
  • left == right (两个指针指向同⼀个位置)
  • left > right (两个指针错开)
快慢指针:⼜称为⻳兔赛跑算法,其基本思想就是使⽤两个移动速度不同的指针在数组或链表等序列结构上移动。
这种⽅法对于处理环形链表数组⾮常有⽤。
其实不单单是环形链表或者是数组,如果我们要研究的问题出现循环往复的情况时,均可考虑使⽤快慢指针的思想。
快慢指针的实现⽅式有很多种,最常⽤的⼀种就是:
在⼀次循环中,每次让慢的指针向后移动⼀位,⽽快的指针往后移动两位,实现⼀快⼀慢

一、复写零

题目链接

题目描述:

题目分析:

题目的意思就是遍历原数组,每遇到一次0,就将后面所有的数水平向右移动一位,并再插入一个0,最后仍丢弃溢出的数据,仍取原来的数组长度的数据。

分析:

如果「从前向后」进⾏原地复写操作的话,由于 0 的出现会复写两次,导致没有复写的数「被覆
盖掉」。因此我们选择「从后往前」的复写策略。
但是「从后向前」复写的时候,我们需要找到「最后⼀个复写的数」,因此我们的⼤体流程分两
步:
  1. 先找到最后⼀个复写的数

我们先初始化两个指针 cur = 0 dest = -1

cur < n 的时候,⼀直执⾏下⾯循环:
判断 cur 位置的元素:
如果是 0 的话, dest 往后移动两位;
否则, dest 往后移动⼀位。
判断 dest 时候已经到结束位置,如果结束就终⽌循环;
如果没有结束, cur++ ,继续判断。

注意:

要判断 dest 是否越界到 n 的位置:
如果越界,执⾏下⾯三步:
  1. n - 1 位置的值修改成 0
  2. cur 向移动⼀步;
  1. dest 向前移动两步。

  2.然后从后向前进⾏复写操作

cur 位置开始往前遍历原数组,依次还原出复写后的结果数组:

判断 cur 位置的值:
1. 如果是 0 dest 以及 dest - 1 位置修改成 0 dest -= 2
2. 如果⾮ 0: dest 位置修改成 0 dest -= 1
cur-- ,复写下⼀个位置

代码实现:

class Solution {public void duplicateZeros(int[] arr) {int len=arr.length,cur=0,dest=-1;while(cur<len){if(arr[cur]==0){dest+=2;}else{dest++;}if(dest==len-1)break;if(dest>len-1){arr[len-1]=0;cur--;dest=len-2;break;}cur++;}if(dest==cur)return;while(cur>=0){if(arr[cur]!=0){arr[dest--]=arr[cur--];}else{arr[dest--]=0;arr[dest--]=0;cur--;}}}
}


二、盛⽔最多的容器

题目描述:

题目分析:

我们可以设两个指针 left right 分别指向容器的左右两个端点,此时容器的容积 :
v = (right - left) * min( height[right], height[left])
容器的左边界为 height[left] ,右边界为 height[right]
为了⽅便叙述,我们假设「左边边界」⼩于「右边边界」
如果此时我们固定⼀个边界,改变另⼀个边界,⽔的容积会有如下变化形式:
  • 容器的宽度⼀定变⼩
  • 由于左边界较⼩,决定了⽔的⾼度。如果改变左边界,新的⽔⾯⾼度不确定,但是可能会超过原来左边界的柱⼦⾼度,因此容器的容积可能会增⼤。
  • 如果改变右边界,⽆论右边界移动到哪⾥,新的⽔⾯的⾼度⼀定不会超过左边界,也就是不会超过现在的⽔⾯⾼度,但是由于容器的宽度减⼩,因此容器的容积⼀定会变⼩的
由此可⻅,左边界和其余边界的组合情况都可以舍去。所以我们可以 left++ 跳过这个边界,继续去判断下⼀个左右边界。
  • 当我们不断重复上述过程,每次都可以舍去⼤量不必要的枚举过程,直到 left right 遇。期间产⽣的所有的容积⾥⾯的最⼤值,就是最终答案。

代码实现:

class Solution {public int maxArea(int[] height) {int l=0,r=height.length-1,max=0,t;while(l<r){if(height[l]<height[r]){t=height[l]*(r-l);l++;}else{t=height[r]*(r-l);r--;}if(max<t)max=t;}return max;}
}


三、有效三⻆形的个数

题目链接

题目描述:

题目分析:

首先我们得知道,三条边能构成三角形的充要条件是:任意两边之和大于第三边。

不过事实上,我们只要保证两条短边和大于最长边即可。

因此,我们可以先将数组从小到大进行排序,接着用一个指针 j 固定一个「最⻓边」,然后在⽐这条边⼩的有序数组中找出⼀个⼆元组,使这个⼆元组之和⼤于这个最⻓边。由于数组是有序的,我们可以利⽤「对撞指针」来优化

设最⻓边枚举到 j 位置,区间 [left, right] 是 j 位置左边的区间(也就是⽐它⼩的区间):

  • 如果 nums[left] + nums[right] > nums[i]

说明 [left, right - 1] 区间上的所有元素均可以与 nums[right] 构成⽐ nums[j] ⼤的⼆元组

则满⾜条件的有 right - left

此时 right 位置的元素的所有情况相当于全部考虑完毕, right-- ,进⼊下⼀轮判断

  •  如果 nums[left] + nums[right] <= nums[i]

说明 left 位置的元素是不可能与 [left + 1, right] 位置上的元素构成满⾜条件的⼆元组

left 位置的元素可以舍去, left++ 进⼊下轮循环

代码实现:

class Solution {public int triangleNumber(int[] nums) {Arrays.sort(nums);int sum=0;for(int j=nums.length-1;j>=2;j--){int l=0,r=j-1;while(l<r){if(nums[l]+nums[r]>nums[j]){sum=sum+r-l;r--;}else{l++;}}}return sum;}
}


 四、三数之和

题目链接

题目描述:

题目分析:

这题其实与上一题十分相似,都是要找一个满足一定条件的三元组,因此同样,我们可以采用先排序,接着用一个指针 j 固定一个数 a,接着在之后的区间内,利用双指针算法找到两数之和等于-a即可

需要注意的是,题目要求进行「去重」操作:

  1. 找到⼀个结果之后, left right 指针要「跳过重复」的元素;
  2. 当使⽤完⼀次双指针算法之后,固定的 a 也要「跳过重复」的元素

代码实现:

class Solution {public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);List<List<Integer>> ans = new ArrayList<List<Integer>>();int n=nums.length;for(int j=0;j<n;){if(nums[j]>0)break;int l=j+1,r=n-1;int target=-nums[j];while(l<r){int sum=nums[l]+nums[r];if(sum==target){ans.add(new ArrayList<Integer>(Arrays.asList(nums[l],nums[r],                                         nums[j])));if(nums[r]==nums[l])break;l++;r--;while(l<r&&nums[r+1]==nums[r])r--;while(l<r&&nums[l-1]==nums[l])l++;}else if(sum>target){r--;}else{l++;    }  }j++;while(j<n&&nums[j]==nums[j-1])j++;}return ans;}
}


五、四数之和

题目链接

题目描述:

题目描述:

这题的思想其实也与三数之和类似,我们只需要先排序,再用一个指针 i 固定一个数 a在这个数 a 的后⾯区间上,利⽤「三数之和」找到三个数,使这三个数的和等于 target - a 即可

代码实现:

class Solution {public List<List<Integer>> fourSum(int[] nums, int target) {int n=nums.length;long t,q;Arrays.sort(nums);List<List<Integer>> ans=new ArrayList<List<Integer>>();for(int i=0;i<n;){t=target;t-=nums[i];//if(t<0)return ans;for(int j=i+1;j<n;){q=t;q-=nums[j];int l=j+1,r=n-1;while(l<r){int sum=nums[l]+nums[r];if(sum==q){List<Integer> list=new ArrayList<Integer>();list.add(nums[i]);list.add(nums[j]);list.add(nums[l]);list.add(nums[r]);ans.add(list);l++;r--;while(l<r&&nums[l]==nums[l-1])l++;while(l<r&&nums[r]==nums[r+1])r--;}else if(sum>q)r--;else l++;}j++;while(j<n&&nums[j]==nums[j-1])j++;}i++;while(i<n&&nums[i]==nums[i-1])i++;}return ans;}
}


 总结

双指针技巧的关键点

  1. 初始化:通常一个指针指向序列的开始位置,另一个指针指向序列的结束位置或某个特定位置。
  2. 移动规则:根据问题的具体情况定义指针的移动规则,如当条件不满足时向前或向后移动。
  3. 更新状态:在每次移动指针之后更新当前的状态,如累加、记录最大值等。
  4. 退出条件:当两个指针相遇或某个指针超出界限时结束循环。

双指针算法是一种简单而有效的算法技巧,通过维护两个指针的状态来简化问题的复杂度。合理地运用双指针法,可以帮助我们在处理数组和字符串问题时更加高效地达成目标。


那么本篇文章就到此为止了,如果觉得这篇文章对你有帮助的话,可以点一下关注和点赞来支持作者哦。如果有什么讲的不对的地方欢迎在评论区指出,希望能够和你们一起进步✊

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

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

相关文章

【HTML+CSS】仿电子美学打造响应式留言板

创建一个响应式的留言板 在这篇文章中&#xff0c;我们将学习如何创建一个简单而美观的留言板&#xff0c;它将包括基本的样式和动画效果&#xff0c;以及响应式设计&#xff0c;确保在不同设备上都能良好显示。 HTML 结构 首先&#xff0c;我们创建基本的HTML结构。留言板由…

Android SQLite的基本使用、生成Excel文件保存到本地

1. Android SQLite的基本使用 1.1. SQLiteOpenHelper Android 底层已经通过一个SQLiteOpenHelper的抽象类将数据库的创建&#xff0c;以及修改&#xff0c;更新等都放在了里面。 要使用它必须实现它的OnCreate(SQLiteDatabase db)&#xff0c;onUpgrade(SQLiteDatabase db, int…

YOLOv11改进 | 独家创新- 注意力篇 | YOLOv11结合全新多尺度线性注意力机制MLAttention(全网独家创新)

1. MLAttention介绍 (1). 多尺度卷积操作&#xff1a;MLAttention通过多尺度卷积操作来增强不同尺度的特征表达能力。采用了多种卷积核尺寸&#xff08;例如5x5、1x7、7x1、1x11、11x1、1x21、21x1&#xff09;的深度可分离卷积来捕捉不同感受野的特征。较小的卷积核擅长捕捉细…

TypeScript 算法手册【快速排序】

文章目录 1. 快速排序简介1.1 快速排序定义1.2 快速排序特点 2. 快速排序步骤过程拆解2.1 选择基准元素2.2 划分数组2.3 递归排序 3. 快速排序的优化3.1 三数取中法选择基准3.2 插入排序与快速排序结合案例代码和动态图 4. 快速排序的优点5. 快速排序的缺点总结 【 已更新完 Ty…

C语言基础(7)之操作符(1)(详细介绍)

目录 1. 各种操作符介绍 1.1 操作符汇总表 2. 移位操作符 2.1 移位操作符知识拓展 —— 原码、反码、补码 2.2 移位操作符讲解 2.2.1 右移操作符 ( >> ) 2.2.2 左移操作符 ( << ) 3. 位操作符 3.1 & (按位与) 3.2 | (按位或) 3.3 ^ (按位异或) 3.4…

排序算法之——归并排序,计数排序

文章目录 前言一、归并排序1. 归并排序的思想2. 归并排序时间复杂度及空间复杂度3. 归并排序代码实现1&#xff09;递归版本2&#xff09;非递归版本 二、计数排序1. 计数排序的思想2. 计数排序的时间复杂度及空间复杂度3. 计数排序代码实现 总结&#xff08;排序算法稳定性&am…

【JavaEE】——线程池大总结

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯&#xff0c; 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01;希望本文内容能够帮助到你&#xff01; 目录 引入&#xff1a;问题引入 一&#xff1a;解决方案 1&#xff1a;方案一——协程/纤程 &#xff08;1…

【完-网络安全】Windows注册表

文章目录 注册表启动项及常见作用五个根节点常见入侵方式 注册表 注册表在windows系统的配置和控制方面扮演了一个非常关键的角色&#xff0c;它既是系统全局设置的存储仓库&#xff0c;也是每个用户的设置信息的存储仓库。 启动项及常见作用 快捷键 WinR打开运行窗口&#x…

【C++】C++基础

目录 一. C关键字(C98) 二、C的第一个程序 三、命名空间 3.1.namespace的价值 3.2.namespace的定义 3.2.命名空间使用 总结&#xff1a;在项目当中第一、第二种方法搭配使用&#xff0c;第三种冲突风险非常大&#xff0c;仅适合练习使用。 四、C输入&输出 五、缺省…

调试分析:[跳数度量]更改为[距离度量]后的 routing_bellmanford 算法

回顾复习2023年8月的《★修改Exata6.2源码&#xff1a;〔修改Bellmanford最短路径路由的衡量标准从【路由跳数】改为【“路由器节点间的物理距离”】&#xff0c;并动画演示〕》&#xff0c;VS2015调试Exata&#xff0c;跟踪调试修改后的[ routing_bellmanford.cpp ]源码&#…

k8s架构,从clusterIP到光电半导体,再从clusterIP到企业管理

clusterIP作为k8s中的服务&#xff0c; 也是其他三个服务的基础 ~]$ kubectl create service clusterip externalname loadbalancer nodeport 客户端的流量到service service分发给pod&#xff0c;pod由控制器自动部署&#xff0c;自动维护 那么问题是service的可用…

计算机网络期末复习真题(附真题答案)

前言&#xff1a; 本文是笔者在大三学习计网时整理的笔记&#xff0c;哈理工的期末试题范围基本就在此范畴内&#xff0c;就算真题有所更改&#xff0c;也仅为很基础的更改数值&#xff0c;大多跑不出这些题&#xff0c;本文包含简答和计算等大题&#xff0c;简答的内容也可能…

【RADARSAT Constellation Mission(RCM)卫星星座简介】

RADARSAT Constellation Mission&#xff08;RCM&#xff09;卫星星座是加拿大太空局&#xff08;CSA&#xff09;的下一代C波段合成孔径雷达&#xff08;SAR&#xff09;卫星星座&#xff0c;以下是对其的详细介绍&#xff1a; 一、基本信息 发射时间&#xff1a;2019年6月…

基于微信小程序的四六级词汇+ssm(lw+演示+源码+运行)

摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;四六级词汇小程序被用户普遍使用&#xff0c;为方便用户能…

容器适配器-stack、queue、priority_queue和仿函数

目录 1.什么是适配器 2.deque 1.简单了解结构 2.deque的缺陷 3.为什么选择deque作为stack和queue的底层默认容器 3.stack&#xff08;栈&#xff09; 4.queue&#xff08;队列&#xff09; 5.仿函数 6.priority_queue&#xff08;优先级队列&#xff09;&#xff08;堆…

微信小程序map组件自定义气泡真机不显示

最近遇到一个需求需要使用uniapp的map自定义气泡 &#xff0c;做完之后发现在模拟器上好好的&#xff0c;ios真机不显示&#xff0c;安卓页数时好时不好的 一番查询发现是小程序的老问题了&#xff0c;网上的方法都试了也没能解决 后来看到有人说用nvue可以正常显示&#xff0c…

会议平台后端优化方案

会议平台后端优化方案 通过RTC的学习&#xff0c;我了解到了端对端技术&#xff0c;就想着做一个节省服务器资源的会议平台 之前做了这个项目&#xff0c;快手二面被问到卡着不知如何介绍&#xff0c;便有了这篇文章 分析当下机制 相对于传统视频平台&#xff08;SFU&#xff…

Nagle 算法:优化 TCP 网络中小数据包的传输

1. 前言 在网络通信中&#xff0c;TCP&#xff08;传输控制协议&#xff09;是最常用的协议之一&#xff0c;广泛应用于各种网络应用&#xff0c;如网页浏览、文件传输和在线游戏等。然而&#xff0c;随着互联网的普及&#xff0c;小数据包的频繁传输成为一个不容忽视的问题。…

828华为云征文 | 云服务器Flexus X实例:向量数据库 pgvector 部署,实现向量检索

目录 一、什么是向量数据库 pgvector &#xff1f; 二、pgvector 部署 2.1 安装 Docker 2.2 拉取镜像 2.3 添加规则 三、pgvector 运行 3.1 运行 pgvector 3.2 连接 pgvector 3.3 pgvector 常见操作 四、总结 本篇文章通过 云服务器Flexus X实例 部署向量数据库 pgve…

Windows11系统下SkyWalking环境搭建教程

目录 前言SkyWalking简介SkyWalking下载Agent监控实现启动配置SkyWalking启动Java应用程序启动Elasticsearch安装总结 前言 本文为博主在项目环境搭建时记录的SkyWalking安装流程&#xff0c;希望对大家能够有所帮助&#xff0c;不足之处欢迎批评指正&#x1f91d;&#x1f91…