双指针算法实战:移动零与复写零详解
基础打牢后,实战演练必不可少。今天用两道经典题目巩固双指针思想,重点在于原地操作和边界处理。
一、移动零
题目描述
给定一个数组 nums,将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。要求必须在原数组上操作,尽量减少总操作次数。
思路解析
这道题的核心是快慢指针。我们需要遍历数组,将非零元素依次移到前面,最后将剩余位置填充为 0。
具体做法如下:
- 定义两个指针,
current用于遍历整个数组,write指向下一个非零元素应该放置的位置。 - 当
current遇到非零元素时,将其与write位置的元素交换(如果两者不重合),然后write向前移动。 - 无论是否交换,
current都继续向后移动。 - 遍历结束后,
write之后的所有位置自然就是 0(或者在交换过程中已经归位)。
注意:这里不需要显式地填充 0,因为交换逻辑保证了非零元素前移,剩下的位置逻辑上即为空,但在实际代码中,为了严谨,通常会在遍历完非零元素后,将 write 到末尾的部分置为 0,或者利用交换特性直接完成。下面的代码采用交换法,逻辑更直观。
代码实现
void Swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
void moveZeroes(int* nums, int numsSize) {
int write = 0;
for (int current = 0; current < numsSize; current++) {
if (nums[current] != 0) {
// 只有当两个指针不重合时才需要交换,避免不必要的操作
if (write != current) {
Swap(&nums[write], &nums[current]);
}
write++;
}
}
}
这段代码提交后能顺利通过,关键在于理解 write 指针始终指向当前待填充的非零位置。
二、复写零
题目描述
在一个固定的整数数组中,将每个出现的 0 复制一遍,并将后续元素向右移动。数组长度固定,超出部分将被截断。
思路解析
如果从前往后遍历,遇到 0 就插入,会覆盖掉后面的元素,导致数据丢失。因此,必须从后往前进行复写。


