Lazy loaded image
😋玩转双指针
Words 2945Read Time 8 min
2025-10-5
2025-10-5
type
status
date
slug
summary
tags
category
icon
password
网址

📝算法解释

双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。也可以延伸到多个数组的多个指针。
若两个指针指向同一数组,遍历方向相同且不会相交,则也称为滑动窗口(两个指针包围的区域即为当前的窗口),经常用于区间搜索。
若两个指针指向同一数组,但是遍历方向相反,则可以用来进行搜索,待搜索的数组往往是
排好序的。

Two Sum

167. 两数之和 II - 输入有序数组

题目描述

在一个增序的整数数组里找到两个数,使它们的和为给定值。已知有且只有一对解。

输入输出样例

输入是一个数组(numbers)和一个给定值(target)。输出是两个数的位置,从 1 开始计数。
在这个样例中,第一个数字(2)和第二个数字(7)的和等于给定值(9)。
 

题解

因为数组已经排好序,我们可以采用方向相反的双指针来寻找这两个数字,一个初始指向最小的元素,即数组最左边,向右遍历;一个初始指向最大的元素,即数组最右边,向左遍历。
如果两个指针指向元素的和等于给定值,那么它们就是我们要的结果。如果两个指针指向元素的和小于给定值,我们把左边的指针右移一位,使得当前的和增加一点。如果两个指针指向元素的和大于给定值,我们把右边的指针左移一位,使得当前的和减少一点。

可以证明,对于排好序且有解的数组,双指针一定能遍历到最优解。证明方法如下:假设最优解的两个数的位置分别是 l 和 r。我们假设在左指针在 l 左边的时候,右指针已经移动到了 r;此时两个指针指向值的和小于给定值,因此左指针会一直右移直到到达 l。同理,如果我们假设在右指针在 r 右边的时候,左指针已经移动到了 l;此时两个指针指向值的和大于给定值,因此右指针会一直左移直到到达 r。所以双指针在任何时候都不可能处于 (l,r) 之间,又因为不满足条件时指针必须移动一个,所以最终一定会收敛在 l 和 r。

归并两个有序数组

88. 合并两个有序数组

88. 合并两个有序数组 - 力扣(LeetCode)
88. 合并两个有序数组 - 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。 注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。   示例 1: 输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 输出:[1,2,2,3,5,6] 解释:需要合并 [1,2,3] 和 [2,5,6] 。 合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。 示例 2: 输入:nums1 = [1], m = 1, nums2 = [], n = 0 输出:[1] 解释:需要合并 [1] 和 [] 。 合并结果是 [1] 。 示例 3: 输入:nums1 = [0], m = 0, nums2 = [1], n = 1 输出:[1] 解释:需要合并的数组是 [] 和 [1] 。 合并结果是 [1] 。 注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。   提示: * nums1.length == m + n * nums2.length == n * 0 <= m, n <= 200 * 1 <= m + n <= 200 * -109 <= nums1[i], nums2[j] <= 109   进阶:你可以设计实现一个时间复杂度为 O(m + n) 的算法解决此问题吗?
88. 合并两个有序数组 - 力扣(LeetCode)

题目描述

给定两个有序数组,把两个数组合并为一个。

输入输出样例

输入是两个数组和它们分别的长度 m 和 n。其中第一个数组的长度被延长至 m + n,多出的 n 位被 0 填补。题目要求把第二个数组归并到第一个数组上,不需要开辟额外空间。

题解

因为这两个数组已经排好序,我们可以把两个指针分别放在两个数组的末尾,即 nums1 的m − 1 位和 nums2 的 n − 1 位。每次将较大的那个数字复制到 nums1 的后边,然后向前移动一位。因为我们也要定位 nums1 的末尾,所以我们还需要第三个指针,以便复制。
在以下的代码里,我们直接利用 m 和 n 当作两个数组的指针,再额外创立一个 pos 指针,起始位置为 m + n −1。每次向左移动 m 或 n 的时候,也要向左移动 pos。这里需要注意,如果nums1 的数字已经复制完,不要忘记把 nums2 的数字继续复制;如果 nums2 的数字已经复制完,剩余nums1 的数字不需要改变,因为它们已经被排好序。

滑动窗口

76. 最小覆盖子串

题目描述

给定两个字符串 s 和 t,求 s 中包含 t 所有字符的最短连续子字符串的长度,同时要求时间复杂度不得超过 O(n)。

输入输出样例

输入是两个字符串 s 和 t,输出是一个 S 字符串的子串。如果不存在解,则输出一个空字符串。
在这个样例中,s 中同时包含一个 A、一个 B、一个 C 的最短子字符串是“BANC”。

题解

本题使用滑动窗口求解,即两个指针 l 和 r 都是从最左端向最右端移动,且 l 的位置一定在r 的左边或重合。Python 题解则直接使用 Counter 数据结构同时统计 t 中存在的字符和其缺少的数量(也可以用 dict 替代)。注意本题虽然在 for 循环里出现了一个 while 循环,但是因为 while 循环负责移动 l 指针,且 l 只会从左到右移动一次,因此总时间复杂度仍然是 O(n)。

快慢指针

142. 环形链表 II

142. 环形链表 II - 力扣(LeetCode)
142. 环形链表 II - 给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。 不允许修改 链表。   示例 1: [https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist.png] 输入:head = [3,2,0,-4], pos = 1 输出:返回索引为 1 的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。 示例 2: [https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2018/12/07/circularlinkedlist_test2.png] 输入:head = [1,2], pos = 0 输出:返回索引为 0 的链表节点 解释:链表中有一个环,其尾部连接到第一个节点。 示例 3: [https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2018/12/07/circularlinkedlist_test3.png] 输入:head = [1], pos = -1 输出:返回 null 解释:链表中没有环。   提示: * 链表中节点的数目范围在范围 [0, 104] 内 * -105 <= Node.val <= 105 * pos 的值为 -1 或者链表中的一个有效索引   进阶:你是否可以使用 O(1) 空间解决此题?
142. 环形链表 II - 力扣(LeetCode)

题目描述

给定一个链表,如果有环路,找出环路的开始点。

输入输出样例

输入是一个链表,输出是链表的一个节点。如果没有环路,返回一个空指针。
在这个样例中,值为 2 的节点即为环路的开始点。
如果没有特殊说明,LeetCode 采用如下的数据结构表示链表。
notion image

题解

对于链表找环路的问题,有一个通用的解法——快慢指针(Floyd 判圈法)。给定两个指针,分别命名为 slow 和 fast,起始位置在链表的开头。每次 fast 前进两步,slow 前进一步。如果fast可以走到尽头,那么说明没有环路;如果 fast 可以无限走下去,那么说明一定有环路,且一定存在一个时刻 slow 和 fast 相遇。当 slow 和 fast 第一次相遇时,我们将 fast 重新移动到链表开头,并让 slow 和 fast 每次都前进一步。当 slow 和 fast 第二次相遇时,相遇的节点即为环路的开始点。
注意 对于某些只需要判断是否存在环路的题目,也可以通过建造哈希表来查重。
 

🤗 练习


基础难度

633. 平方数之和

Two Sum 题目的变形题之一。

680. 验证回文串 II

Two Sum 题目的变形题之二。

524. 通过删除字母匹配到字典里最长单词

归并两个有序数组的变形题。

进阶难度

需要利用其它数据结构方便统计当前的字符状态。
Given a string, find the length of the longest substring T that contains at most  k  distinct characters.
Example 1:
Example 2:
这道题是之前那道Longest Substring with At Most Two Distinct Characters的拓展,而且那道题中的解法一和解法二直接将2换成k就行了:
解法一:
 
解法二:
上一篇
下一篇
Sora使用教程资料

Comments
Loading...