优选算法------双指针(算法原理+力扣题)
文章摘要:本文深入解析双指针算法的核心思想与实战应用,涵盖同向、相向、快慢指针三大经典场景。通过移动零、复写零、快乐数、盛最多水的容器、有效三角形的个数、和为s的两个数、三数之和等七道力扣高频题目,系统讲解算法原理、解题思路与代码实现,助你快速掌握双指针技巧,提升算法解题效率。
目录
1.移动零
2.复写零
3.快乐数
4.盛最多水的容器
5.有效三角形的个数
6.和为s的两个数
7.三数之和
双指针简介
常⻅的双指针有两种形式,⼀种是对撞指针,⼀种是快慢指针。
对撞指针:⼀般⽤于顺序结构中,也称左右指针。
- 对撞指针从两端向中间移动。⼀个指针从最左端开始,另⼀个从最右端开始,然后逐渐往中间逼
近。 - 对撞指针的终⽌条件⼀般是两个指针相遇或者错开(也可能在循环内部找到结果直接跳出循
环),也就是:- left == right (两个指针指向同⼀个位置)
- left > right (两个指针错开)
快慢指针 :⼜称为⻳兔赛跑算法,其基本思想就是使⽤两个移动速度不同的指针在数组或链表等序列
结构上移动。
这种⽅法对于处理环形链表 或数组 ⾮常有⽤。
其实不单单是环形链表或者是数组,如果我们要研究的问题出现循环往复 的情况时,均可考虑使⽤快
慢指针的思想。
快慢指针的实现⽅式有很多种,最常⽤的⼀种就是:
- 在⼀次循环中,每次让慢的指针向后移动⼀位,⽽快的指针往后移动两位,实现⼀快⼀慢。
正文
1.移动零
-
题目链接 :移动零
-
题目描述 :

-
算法原理:双指针(定义数组下标模拟指针)
cur:用来遍历数组dest:指向已经处理过的区间内,非零元素的最后一个元素
大概思路 :先定义两个指针,cur用来遍历数组,从第一个元素开始遍历,所以cur=0;
dest用来指向处理过 的数组中,最后一个非零元素,cur等于0,还没有进行处理,所以dest=-1;
当numscur!=0,交换numscur,numdest++;
直到遍历整个数组
代码:

2.复写零
-
题目链接 :复写零
-
题目描述 :

-
算法原理:双指针(定义数组下标模拟指针)
cur:遍历需要复写的部分数组dest:指向已经复写的最后一个元素
大概思路 :由于从前往后复写 时,就地解决,遇到零时要复写两次,会导致后面没有被cur遍历的元素被覆盖 。因此我们考虑从后往前复写 。
从后往前复写:
- 1.
cur找到最后一个要复写的数- 1.1判断
cur的值 - 1.2.决定
dest走一步还是两步 - 1.3.判断
dest是否越界 - 1.4.
cur++
- 1.1判断
- 2.考虑特殊情况:当最后一个复写数是0,复写两次,但是在复写之前,dest已经到达了arr.length-2,复写两次会导致dest=arr.lenth导致数组越界。这个时候就要我们手动处理最后一个要复写的数,即0,只需要复写一遍。给出一组特殊情况的数组,可自己模拟:1,0,2,3,0,4
- 3.从后往前复写,!0复写一边,0复写两边

代码 :

3.快乐数
-
题目链接 :快乐数
-
题目描述 :

-
算法原理:快慢双指针(定义数组下标模拟指针)
slow:每次走一步fast:每次走两步
大概思路:
- 问题转化:将数字按"快乐数"规则(每位平方和)不断迭代,看作一个隐式的链表。每个数字是链表的一个节点,其下一个节点是它各位平方和得到的数字。
- 判断循环 :如果迭代过程中出现
1,则链表到达"终点",该数是快乐数。如果进入循环(即出现之前出现过的数字),则该数不是快乐数。 - 快慢指针法 :
- 定义两个"指针"
slow和fast,初始都等于原始数字n。 slow每次计算一次各位平方和(走一步),fast每次计算两次各位平方和(走两步)。- 如果
fast最终等于1,说明是快乐数。 - 如果
fast和slow相遇(值相等)且不等于1,说明进入了循环,不是快乐数。

代码 :

- 定义两个"指针"
4.盛最多水的容器
-
题目 :盛最多水的容器
-
题目描述 :

-
算法原理:相撞双指针(定义数组下标模拟指针)
left:水柱左侧right:水柱右侧
大概思路 :

代码 :
5.有效三角形的个数
-
题目链接 :有效三角形的个数
-
题目描述 :

-
算法原理:双指针
left:指向aright:指向b
法一:暴力枚举,但是会超时
法二:利用单调性,使用双指针
大概思路:固定最大数c;在最大数的左区间,使用双指针算法,根据最小的两边之和大于第三边,即a+b>c,快速统计出符合要求的三元组的个数

代码 :

6.和为s的两个数
- 题目链接 :和为s的两个数
- 题目描述 :

大概思路:
- 问题转化 :在递增排序 的数组中,寻找两个数,使它们的和等于目标值
target。 - 双指针法 :
- 初始化两个指针:
left指向数组起始位置(最小元素),right指向数组末尾(最大元素)。 - 计算当前和
sum = nums[left] + nums[right]。 - 如果
sum == target,找到答案,返回这两个数。 - 如果
sum < target,说明当前和太小,需要增大,因此left右移(选择更大的数)。 - 如果
sum > target,说明当前和太大,需要减小,因此right左移(选择更小的数)。
- 初始化两个指针:
代码 :

7.三数之和
- 题目链接 :三数之和
- 题目描述 :

大概思路:
- 1.排序;
- 2.固定一个数numsi;
- 3.在该数的后面区间,利用"双指针算法"快速找到两个数为-numsi(此步原理同求两数之和的算法原理);
- 细节问题:
- 1.去重:找到一种结果之后 ,left和right要跳过重复的元素;使用完一次双指针之后,i也要跳过重复的元素。
- 2.不漏:找到一种结果之后,缩小区间,继续找。
代码:

练习:四数之和
提示:排序+固定一个数+三数之和算法原理(同样注意去重)
- 细节问题: