双指针算法基础
在处理数组或链表相关的算法题时,双指针是一种非常高效且常用的技巧。它主要包含两种形态:对撞指针和快慢指针。理解这两种模式的区别与应用场景,能帮你快速定位解题思路。
1. 对撞指针
对撞指针通常用于顺序结构(如数组)。两个指针分别从两端向中间移动,一个指向最左端,另一个指向最右端,逐渐逼近。终止条件通常是两指针相遇(left == right)或错开(left > right)。
2. 快慢指针
又称龟兔赛跑算法,核心思想是使用两个移动速度不同的指针在序列上遍历。这在处理环形链表或需要寻找特定相对位置的问题时非常有效。最常见的实现是在一次循环中,慢指针每次移动一位,快指针每次移动两位。
01、移动零
题目来源:LeetCode 283. Move Zeroes
题目描述
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。必须在原数组上操作,尽量减少总操作次数。
算法思路
这道题的核心在于如何在不破坏非零元素顺序的前提下完成移动。我们可以借鉴快速排序中的分区思想,将数组划分为两部分:左侧是非零元素区,右侧是零元素区。
具体策略是使用两个指针:
- cur:负责扫描整个数组。
- dest:记录非零序列的最后一个位置。
在遍历过程中,保证 [0, dest] 区间内全是非零元素,[dest+1, cur-1] 区间内全是零。
算法流程
- 初始化
cur = 0,dest = -1。初始时dest为-1表示尚未发现非零元素。 - 遍历数组:
- 如果
nums[cur]为0,直接跳过,cur++。此时dest不变,[dest+1, cur-1]自然维持为零区间。 - 如果
nums[cur]不为0,说明遇到了新的非零元素。先将dest自增,将其指向下一个可放置非零元素的位置,然后交换nums[dest]和nums[cur],最后cur++。
- 如果
这样,每当遇到非零数,就把它'挪'到当前非零区的末尾,原本该位置的 0 会被交换到后面去。
C++ 代码演示
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int dest = -1; // 指向非零元素区间的最后一个位置
int cur = ;
(cur != nums.()) {
(nums[cur]) {
(nums[++dest], nums[cur]);
}
cur++;
}
}
};





