双指针算法基础
在解决数组或链表问题时,双指针是一种非常高效的技巧。常见的双指针主要有两种形式:对撞指针和快慢指针。
对撞指针(左右指针) 通常用于有序序列。一个指针从最左端开始,另一个从最右端开始,逐渐向中间逼近。终止条件通常是两个指针相遇(
left == right)或者错开(left > right)。快慢指针(龟兔赛跑) 适用于检测循环或寻找中点等场景。在一次遍历中,慢指针每次移动一位,快指针每次移动两位。如果存在环,快指针最终会追上慢指针。
注意:这里的'指针'并非 C 语言中的地址指针,而是指记录数组下标的变量。
283. 移动零
题目描述
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。必须在不复制数组的情况下原地修改。
核心思路
对撞指针在这里不太适用,因为我们需要保持非零元素的相对顺序。更合适的方案是两个指针都从左端出发:
- 定义
cur指针用于遍历数组查找非零元素。 - 定义
dest指针指向当前应该放置非零元素的位置(初始化为-1)。 - 当
cur遇到非零元素时,dest向前移动一位,然后交换nums[dest]和nums[cur]。 - 当
cur遍历完数组,所有非零元素已按序前置,剩余的0自然位于末尾。
代码实现
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int size = nums.size();
int dest = -1; // 指向待填充位置的前一个
int cur = 0; // 遍历指针
while (cur < size) {
if (nums[cur] != 0) {
dest++;
swap(nums[dest], nums[cur]);
}
cur++;
}
}
};
本地测试示例
int {
Solution s;
vector<> v1{, , , , , , };
vector<> v2{, , , , , };
s.(v1);
( e : v1) cout << e << ;
cout << endl;
s.(v2);
( e : v2) cout << e << ;
;
}


