【双指针】经典数组双指针题LeetCode
文章目录
- 27. 移除元素 简单
- 283. 移动零 简单🔥
- 167. 两数之和 II - 输入有序数组 中等
- 11. 盛最多水的容器 中等🔥
- 15. 三数之和 中等(N数之和)中等🔥
- 42. 接雨水 困难 🔥
- 26. 删除有序数组中的重复项 简单
- 5. 最长回文子串 中等
27. 移除元素 简单
题目链接
给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1:输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
示例 2:输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
思路:双指针
- right指针不是val就赋值给left,right++,left++
- right指针是val就跳过,right++
代码:
class Solution {public int removeElement(int[] nums, int val) {int left = 0,right = 0;while(right<nums.length){if(nums[right]!=val){nums[left] = nums[right];left++;}right++;}return left;}
}
283. 移动零 简单🔥
题目链接
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]
输出: [0]
思路: 前后双指针,将每一个不是0的元素赋值给前面的指针,对未重新赋值的部分赋值0。
代码:
class Solution {public void moveZeroes(int[] nums) {int left = 0;int right = 0;// 依次将right指针指向的非0元素赋值给left指针while(right<nums.length){if(nums[right]!=0){nums[left] = nums[right];left++;}right++;}// 从 left 开始 赋值0for(int i = left; i < nums.length;i++){nums[i] = 0;}}
}
167. 两数之和 II - 输入有序数组 中等
题目链接
给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。
以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。
你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
你所设计的解决方案必须只使用常量级的额外空间。
示例 1:输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
示例 2:输入:numbers = [2,3,4], target = 6
输出:[1,3]
解释:2 与 4 之和等于目标数 6 。因此 index1 = 1, index2 = 3 。返回 [1, 3] 。
示例 3:输入:numbers = [-1,0], target = -1
输出:[1,2]
解释:-1 与 0 之和等于目标数 -1 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
思路:在已排序数组(非递减)的前提条件下,Left指针指向第一个元素,Right指针指向最后一个元素。当两者大于目标值时,移动Left指针(left++),小于目标值时,移动Right指针(right–),直到找到目标答案。
代码:
class Solution {public int[] twoSum(int[] numbers, int target) {int left = 0;int right = numbers.length-1;while(left!=right){if(numbers[left]+numbers[right]==target){ // 等于目标值return new int[]{left+1,right+1};}if(numbers[left]+numbers[right]>target){ // 大于目标值,通过right-- 以缩小两者的和right--;}else{ // 小于目标值,通过left++ 以扩大两者的和left++;}}return new int[]{-1,-1};}
}
11. 盛最多水的容器 中等🔥
题目链接
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。

思路:该题首先想到的思路就是暴力搜索,两个For循环寻找最大值,但是时间复杂度过高。我们知道计算机两条线中间容器所盛水的容量取决于两条线中的短边,为了计算容量的最大值,我们只需要更改短边即可。因此,采用左右双指针法,每次移动短边所在的指针,以寻找最大容量。
代码:
class Solution {public int maxArea(int[] height) {// 左右指针int left = 0;int right = height.length - 1;int result = 0;while(left<right){// 计算当前盛水量int currentResult = Math.min(height[left],height[right]) * (right-left);// 更新结果result = Math.max(result,currentResult);// 左右指针所在的两条线谁矮谁移动,以求最大值if(height[left]<height[right]){left++;}else{right--;}}return result;}
}
15. 三数之和 中等(N数之和)中等🔥
题目链接
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
示例 2:输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
示例 3:输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。
思路:
- 先将数组排序,将三数之和化简为二数之和问题;先固定一个值,寻找另外两个值。
- 二数问题依旧采用双指针法解决,但需要考虑答案重复问题,每次移动指针,比如left和left++所在的值一样,则会重复寻找,因此继续++,直到不同。
- 在数组中,从第一个值开始依次选取一个值进行固定,在其后面的数组中继续寻找另外两个值。(不用再寻找固定值前面的值,否则依旧会重复查找)。
- 可以将三数之和问题扩展为N数之和问题,将目标和为0改为target。通过递归法将问题不断缩小。
- 5数之和->就是把每一个4数之和的答案加上固定的那个值,就是5数之和的答案。
代码(N数之和):
class Solution {public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums); // 先排序 return nSumTarget(nums,0,0,3); // 3数之和等于0}/**nSumTarget:可以解决N sum问题参数:- nums:数组- target:目标值- start:只在[start,nums.length-1]区间寻找- needNum:需要几个数,两数之和就是2,三数之和就是3*/public List<List<Integer>> nSumTarget(int[] nums,int target,int start,int needNum){List<List<Integer>> res = new ArrayList<>();if(needNum<2 || nums.length<needNum) return res;if( needNum == 2){ // 同理 二数之和int left = start,right = nums.length-1;while(left<right){int leftnum = nums[left];int rightnum = nums[right];if(leftnum+rightnum == target){res.add(new ArrayList<Integer>(Arrays.asList(leftnum,rightnum)));while(left<right && nums[right]==rightnum)right--; // right-- 所在的值如果和right一样,则重复寻找了,因此寻找一个和原来right不一样的,即去重while(left<right && nums[left] == leftnum)left++; // 同理,去重}else if(leftnum+rightnum < target){while(left<right && nums[left] == leftnum)left++; // 同理,去重} else if(leftnum+rightnum > target){while(left<right && nums[right]==rightnum)right--;// 同理,去重}}return res;}else{ // 先定下一个数,将问题规模缩小for(int i = start; i < nums.length;i++){int cur = nums[i]; List<List<Integer>> re = nSumTarget(nums,target-cur,i+1,needNum-1); // 递归调用for(List<Integer> r:re){r.add(cur);// 将定下的数加入到每个字问题的答案中res.add(r);// 将r加入到最终答案中}while(i+1 < nums.length && nums[i]==nums[i+1]) i++; // 同理,去重}return res; // 最终答案}}
}
42. 接雨水 困难 🔥
题目链接
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

思路:

除了最两边的位置不可能盛水以外,中间位置的盛水量受左右两边高度的影响,主要取决于较小的一边的最大高度。
代码:
class Solution {public int trap(int[] height) {int len = height.length;if(len<=2)return 0; // base case int[] leftMaxHeight = new int[len]; // 计算每个节点左侧出现过的最大高度(包括当前节点)int[] rightMaxHeight = new int[len];// 计算每个节点右侧出现过的最大高度(包括当前节点)int leftMax = 0;for(int i = 0; i < len;i++){leftMax = Math.max(leftMax,height[i]);leftMaxHeight[i] = leftMax;}int rightMax = 0;for(int i = len-1; i >= 0; i--){rightMax = Math.max(rightMax,height[i]);rightMaxHeight[i] = rightMax;}int res = 0;for(int i = 1;i< len-1;i++){res += Math.min(leftMaxHeight[i],rightMaxHeight[i]) - height[i];}return res;}
}
是否可以再次简化?
通过定义左右双指针,left = 0 和 right = length-1,同时求出leftMaxHeight和rightMaxHeight。并在这个过程中,求出每个位置的盛水量。

class Solution {public int trap(int[] height) {int len = height.length;if(len<=2)return 0; // base case // 左右指针int left = 0,right = len - 1;// 记录左/右指针的左/右边的最大值(包括左/右节点)int leftMax = 0;int rightMax = 0;int res = 0;while(left<=right){leftMax = Math.max(leftMax,height[left]);rightMax = Math.max(rightMax,height[right]);if(leftMax < rightMax){// 此时,left位置的 Min(左边最大,右边最大)已经确定,就是【左边最大】,即leftMaxres += leftMax - height[left];left++;}else{// 同理res += rightMax - height[right];right--;}}return res;}
}
26. 删除有序数组中的重复项 简单
题目链接
给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。
考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:
更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
返回 k 。
示例 1:输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
示例 2:输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
思路:快慢指针,快指针如果不等于慢指针,就将快指针的值赋给慢指针的下一个。
代码:
class Solution {public int removeDuplicates(int[] nums) {int left = 0;int right = 0;while(right<=nums.length-1){if(nums[right]!=nums[left]){nums[++left] = nums[right];right++;}else{right++;}}return left+1;}
}
5. 最长回文子串 中等
题目链接
给你一个字符串 s,找到 s 中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例 1:
输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。
示例 2:
输入:s = “cbbd”
输出:“bb”
思路:
- 通过双指针从中间向外扩,判断回文
- 依次选择原字符串的中间节点
- 注意奇数数量和偶数数量的回文串中间节点个数不一样
代码:
class Solution {public String longestPalindrome(String s) {String result = null;result = s.substring(0,1);String r;// 遍历每一个字符,将其作为回文串的中心向外扩展for(int i = 1; i < s.length(); i++) {r = Palindrome(s,i,i);// 寻找奇数个的回文子串if(r.length()>result.length())result = r;r = Palindrome(s,i-1,i);// 寻找偶数个的回文子串if(r.length()>result.length())result = r;}return result;}/*** 返回以s[a]与s[a]为中心的最大回文字串,a可以等于b 或者 a+1 = b* ps:一种回文串为偶数个,中心两个字母、另一种为奇数个,中心一个字母* @param s* @param a* @param b* @return*/public String Palindrome(String s,int a,int b) {// 若s[a]!=s[b] return ""if(s.charAt(a) != s.charAt(b))return "";while (a >= 0 && b<s.length() ){if(s.charAt(a) == s.charAt(b)){a--;b++;}else break;}a = a+1;b = b-1;return s.substring(a,b+1);}
}
参考:
1.《labuladong的算法小抄》
2. https://labuladong.github.io/algo/di-yi-zhan-da78c/shou-ba-sh-48c1d/shuang-zhi-fa4bd/
3. LeetCode Hot 100 🔥
相关文章:
【双指针】经典数组双指针题LeetCode
文章目录 27. 移除元素 简单283. 移动零 简单🔥167. 两数之和 II - 输入有序数组 中等11. 盛最多水的容器 中等🔥15. 三数之和 中等(N数之和)中等🔥42. 接雨水 困难 🔥26. 删除有序数组中的重复项 简单5. 最…...
极智嘉x吉利汽车 x京东物流,引领汽车行业智慧物流新变革!
近日,中国领先的汽车制造商吉利汽车携手中国领先的技术驱动的供应链解决方案及物流服务商京东物流、全球仓储机器人引领者极智嘉(Geek),在西安吉利汽车制造基地RDC仓库率先落地SkyPick上存下拣解决方案,实现了全物流链精益化、智能化、一体化…...
RK3588平台开发系列讲解(AI 篇)RKNN C API 详细说明
文章目录 一、API 硬件平台支持说明二、API 函数介绍2.1、rknn_init2.2、rknn_destroy2.3、rknn_query2.4、rknn_inputs_set2.5、rknn_run2.6、rknn_outputs_get2.7、rknn_outputs_release沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章主要讲解 RKNN C API 详细…...
【基础】Android Handler
一、博客参考 Handler机制详解【重点】:https://www.jianshu.com/p/b4d745c7ff7a Handler Thread工作线程操作UI范例【重点】:https://www.cnblogs.com/net168/p/4075126.html 二、内存泄漏的解决:静态内部类弱引用 关于 Handler…...
c语言实现MD5算法
MD5加密 文章目录 MD5加密MD5介绍应用场景代码分析 (基于qt5.14.2)测试记录 MD5介绍 1。 一种单向加密算法,即对明文加密,而不能通过密文得到明文。对原数据的任何改动,哪怕是1字节,得到的MD5值都有很大的区…...
Apache Doris 2.0.0 特性分析
1、存算分离 所谓存算分离是指查询外表时,使用一种专门做计算的BE节点,但对于存储在BE上的内部表,目前还不能做到存储分离。 doris可以查询外部表,包括: Hive、Iceberg、Hudi、Elasticsearch、JDBC、Paimon 早期版本中…...
如何做H5性能测试?
提起H5性能测试,可能许多同学有所耳闻,但是不知道该如何对H5做性能测试,或者不知道H5应该关注哪些性能指标。今天我们就来看下,希望阅读本文后,能够有所了解。 常用指标 1、H5性能相关参数介绍 白屏时间:…...
【Docker】Docker Desktop配置资源:cpu、内存等(windows环境下)
Docker Desktop配置资源:cpu、内存等(windows环境下) 一、WSL2 以及 hyper-v区别,二者安装docker desktop1.WSL2和hyper-v区别2.安装Docker Desktop 二、docker desktop限额配置,资源配置方法 Docker 是指容器化技术&a…...
8.2.tensorRT高级(3)封装系列-内存管理的封装,内存的复用
目录 前言1. 内存管理封装2. 补充知识总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程,之前有看过一遍,但是没有做笔记,很多东西也忘了。这次重新撸一遍,顺便记记笔记。 本次课程学习 tensorRT 高级-内存管理的封装&…...
Keepalived入门指南:实现故障转移和负载均衡
文章目录 一、简介1. Keepalived概述2. 高可用性和负载均衡的重要性 二、故障转移1. 什么是故障转移2. Keepalived的故障转移原理a) VRRP协议b) 虚拟路由器ID和优先级 3. 配置Keepalived实现故障转移a) 主备服务器的设置b) 监控网络接口c) 虚拟IP的配置d) 备份服务器接管流程 三…...
cuOSD(CUDA On-Screen Display Library)库的学习
目录 前言1. cuOSD1.1 Description1.2 Getting started1.3 For Python Interface1.4 Demo1.5 Performance Table 2. cuOSD案例2.1 环境配置2.2 simple案例2.3 segment案例2.4 segment2案例2.5 polyline案例2.6 comp案例2.7 perf案例 3. cuOSD浅析3.1 simple_draw函数 4. 补充知…...
c++函数指针基本用法
将函数像变量一样传递,实际上拿到的是函数的地址,由于函数类型的多样,可以使用auto关键字,可以使用 void(*function2)() ,不过它太繁琐,因此使用typedef 起个名字 typedef void(*HelloWorldFunction)(); 叫…...
Java创建对象的几种方式
在Java中,对象是程序中的一种基本元素,它通过类定义和创建。本篇教程旨在介绍Java中创建对象的几种方式,包括使用new关键字、反射、clone、反序列化等方式。 使用new关键字创建对象 在Java中,最常用的创建对象方式是使用new关键…...
Docker实战专栏简介
🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…...
解放数据库,实时数据同步利器:Alibaba Canal
文章首发地址 Canal是一个开源的数据库增量订阅&消费组件,主要用于实时数据同步和数据订阅的场景,特别适用于构建分布式系统、数据仓库、缓存更新等应用。它支持MySQL、阿里云RDS等主流数据库,能够实时捕获数据库的增删改操作ÿ…...
机器学习基础之《分类算法(3)—模型选择与调优》
作用是如何选择出最好的K值 一、什么是交叉验证(cross validation) 1、定义 交叉验证:将拿到的训练数据,分为训练和验证集。以下图为例:将数据分成5份,其中一份作为验证集。然后经过5次(组)的测试&#x…...
Datawhale Django后端开发入门 TASK03 QuerySet和Instance、APIVIew
一、QuerySet QuerySet 是 Django 中的一个查询集合,它是由 Model.objects 方法返回的,并且可以用于生成数据库中所有满足一定条件的对象的列表。 QuerySet 在 Django 中表示从数据库中获取的对象集合,它是一个可迭代的、类似列表的对象集合。主要特点…...
Python 网页解析中级篇:深入理解BeautifulSoup库
在Python的网络爬虫中,BeautifulSoup库是一个重要的网页解析工具。在初级教程中,我们已经了解了BeautifulSoup库的基本使用方法。在本篇文章中,我们将深入学习BeautifulSoup库的进阶使用。 一、复杂的查找条件 在使用find和find_all方法查找…...
IDEA 如何制作代码补丁?IDEA 生成 patch 和使用 patch
什么是升级补丁? 比如你本地修复的 bug,需要把增量文件发给客户,很多场景下大家都需要手工整理修改的文件,并整理好目录,这个很麻烦。那有没有简单的技巧呢?看看 IDEA 生成 patch 和使用 patch 的使用。 介…...
Redis专题-秒杀
Redis专题-并发/秒杀 开局一张图,内容全靠“编”。 昨天晚上在群友里看到有人在讨论库存并发的问题,看到这里我就决定写一篇关于redis秒杀的文章。 1、理论部分 我们看看一般我们库存是怎么出问题的 其实redis提供了两种解决方案:加锁和原子操…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...
