Lesson9 字符串双指针算法专题
双指针(Two Pointers):指的是在遍历元素的过程中,不是使用单个指针进行访问,而是使用两个指针进行访问,从而达到相应的目的。如果两个指针方向相反,则称为「对撞指针」。如果两个指针方向相同,则称为「快慢指针」。如果两个指针分别属于不同的数组 / 链表,则称为「分离双指针」;本章仅针对字符串对撞指针进行介绍和题目分析。
1 对撞指针
对撞指针:指的是两个指针left、right分别指向序列第一个元素和最后一个元素,然后left指针不断递增,right不断递减,直到两个指针的值相撞(即 left== right),或者满足其他要求的特殊条件为止。
1.1 对撞指针解题步骤
- 使用两个指针left,right。left指向序列第一个元素,即:
left=0
,right指向序列最后一个元素,即:right=len(nums)-1
。 - 在循环体中将左右指针相向移动,当满足一定条件时,将左指针右移,
left+=1
。当满足另外一定条件时,将右指针左移,right-=1
。 - 直到两指针相撞(即
left==right
),或者满足其他要求的特殊条件时,跳出循环体。
1.2 对撞指针伪代码模版
Python | |
---|---|
1.3 对撞指针适用范围
对撞指针一般用来解决有序数组或者字符串问题:
- 查找有序数组中满足某些约束条件的一组元素问题:比如二分查找、数字之和等问题。
- 字符串反转问题:反转字符串、回文数、颠倒二进制等问题。
2 例题讲解
2.1 LC 344 反转字符串
问题描述
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s
的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
思路分析
对于长度为 N 的待被反转的字符数组,我们可以观察反转前后下标的变化,假设反转前字符数组为 s[0] s[1] s[2] ... s[N - 1],那么反转后字符数组为 s[N - 1] s[N - 2] ... s[0]。比较反转前后下标变化很容易得出 s[i] 的字符与 s[N - 1 - i] 的字符发生了交换的规律,因此我们可以得出如下双指针的解法:
- 将 left 指向字符数组首元素,right 指向字符数组尾元素。
- 当 left < right:
- 交换 s[left] 和 s[right];
- left 指针右移一位,即 left = left + 1;
- right 指针左移一位,即 right = right - 1。
- 当 left >= right,反转结束,返回字符数组即可。
提示
- 字符数组是可变的,但你不能使用额外的数组空间,因此需要在原地修改字符顺序。
参考解答1
Python | |
---|---|
参考解答2
Python | |
---|---|
调用函数法
2.2 LC 125 验证回文串
问题描述
如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。
字母和数字都属于字母数字字符。
给你一个字符串 s
,如果它是 回文串 ,返回 true
;否则,返回 false
。
提示
- 需要忽略字符串中的空格、标点符号等非字母数字字符,并且在判断回文时不区分大小写。
- 可以使用双指针从两端向中间移动,逐字符检查是否相等。
思路分析
最简单的方法是对字符串 s
进行一次遍历,并将其中的字母和数字字符进行保留,放在另一个字符串 sgood
中。这样我们只需要判断 sgood
是否是一个普通的回文串即可。使用双指针,从字符串的两端向中间遍历,逐个比较对应字符。
参考解答
Python | |
---|---|
切片法
Python | |
---|---|
3 举一反三
3.1 LC 345 反转字符串中的元音字母
问题描述
给你一个字符串 s
,仅反转字符串中的所有元音字母,并返回结果字符串。
元音字母包括 'a'
、'e'
、'i'
、'o'
、'u'
,且可能以大小写两种形式出现不止一次。
提示
- 你需要在原地反转字符串中的元音字母,同时保持其他字符的位置不变。
- 注意处理大小写不敏感的元音字符。
思路分析
我们可以使用两个指针 l
和 r
对字符串相向地进行遍历。
- 指针
l
初始时指向字符串s
的首位,指针r
初始时指向字符串s
的末位。 - 在遍历的过程中,不停地将
l
向右移动,直到l
指向一个元音字母(或者超出字符串的边界范围);同时,不停地将r
向左移动,直到r
指向一个元音字母。 - 此时,如果
l < r
,那么交换l
和r
指向的元音字母,否则说明所有的元音字母均已遍历过,就可以退出遍历的过程。
参考解答
3.2 LC 917 仅仅反转字母
问题描述
给你一个字符串 s
,根据下述规则反转字符串:
- 所有非英文字母保留在原有位置。
- 所有英文字母(小写或大写)位置反转。
返回反转后的 s
。
提示
- 只需要反转字母,其他字符保持不变。
- 可以使用双指针法来遍历和交换字母。
思路分析
使用双指针法:
l
指针从左向右遍历,寻找第一个字母;r
指针从右向左遍历,寻找最后一个字母;- 交换这两个字母并移动指针,直到
l
和r
相遇。
参考示例
Python | |
---|---|
3.3 LC 680 验证回文串 II
问题描述
给你一个字符串 s
,最多 可以从中删除一个字符。
请你判断 s
是否能成为回文字符串:如果能,返回 true
;否则,返回 false
。
提示
- 需要考虑最多删除一个字符后字符串是否可以成为回文。
- 可以使用双指针法,遇到不匹配时尝试删除左边或右边的一个字符。
思路分析
首先进行回文串的验证,如果发现不匹配的字符,尝试跳过一个字符并继续验证。具体方法是:
- 使用双指针,分别从字符串两端向中间遍历。
- 一旦发现两个字符不匹配,可以尝试删除左边或右边的一个字符,再判断删除后的字符串是否为回文串。
参考解答
Python | |
---|---|
课后练习
题目编号 | 题目名称 | 主要考点 |
---|---|---|
151 | 反转字符串中的单词 | 字符串反转,空格处理 |
392 | 判断子序列 | 子序列判断,双指针 |
541 | 反转字符串 II | 分段字符串反转,迭代处理 |
1332 | 删除回文子序列 | 回文判断,字符串删除 |