LeetCode总结 (一)双指针
数组的双指针题型搞不好就容易翻车:指针该如何移动覆盖所有可能的情况,循环终止的边界条件、重复情形的剪枝等细节,加在一起思路就糊了,可谓是苦主。LeetCode上的双指针题型典型的有这些(标记为红色的是苦主):
- 3. 无重复字符的最长子串(阿基里斯与龟:一次遍历,前后两个指针确定长度,遇到重复则前指针放弃若干位,后指针开辟疆土)
看似简单,实际上很坑。一个坑点是当重复的两个元素是相邻时,此时需要重置左右指针;另一个坑点是维护一个集合,里面存放当前的左右指针内所有元素;
- 11. 盛最多水的容器 (两边交替包抄:一次遍历,左右两个指针从两边向中间推进,当然每次是放弃较小的那一边,如果移动之后数组值还变小了,则直接continue)
- 15. 三数之和 (左指针遍历,中右包抄:O(n^2) 先排序)
如何去重需要注意。
另一种解法是从两边包抄,中间遍历,但是根本不对!因为每次得到一组解后,移动左指针或者右指针都有可能错过一些解!
- 16. 最接近的三数之和(左指针遍历中右包抄: O(n^2) 循环一次左边界指针,然后让中指针和右指针从两边包抄(相邻相等元素跳过从而去重))
- 18. 四数之和(固定左边一个位置,转化为15题三数之和问题)
- 42. 接雨水 (左右指针追逐)
这道题比较灵活,没套路。
1. 取left与right两个相邻指针,如果right较大则都右移,直到left较大为止;
2. 然后移动right,累加深度,在比left更大时把深度变现,并更新left和right;
3. 重复2步骤,如果一直到末尾也没变现,则麻烦了,有bug;
4. 为了解决边界bug的问题,我们将数组reverse,再运行一遍上面的步骤就好了;
5. 为了优化计算,不用reverse,而是记录最后一次变现的位置作为哨兵,再反向遍历到哨兵位置即可。
- 75. 荷兰国旗排序
这道题脱离套路,从指针代表什么意义、初始化方式到移动规则,终止规则都与其他题目不同。
- 345. 交换元音字母 左右两个指针包抄
最重要的是指针的意义
- 单纯用于遍历,一般是左指针,约束当前只考虑左指针在这里的情况;
- 左右两个哨兵,检查当前情况后移动其中某一个;
- 左右两个哨兵,中间一个指针遍历;
- 前后两个指针追逐,检查当前情况后移动其中某一个
- 如果不是以上套路,则原则上就是要指针每次都能移动,且覆盖所有可能的情形
坑点:
1. 去重:什么时候相邻两元素相同则直接跳过,这时候要注意直接跳过不会错过可能的解;
2. 指针的意义:在整个过程中,指针代表的意义都是一致的(作为边界);作为边界一般是开区间(即第一个和最后一个元素默认为初始的指针,但是未必满足条件)
·