1. 问题背景与需求分析
- 复写零是力扣(LeetCode)上一道经典的数组操作题目,考察对双指针技巧的掌握程度。题目要求:给定一个固定长度的整数数组,遇到零就复制一个零插入其后,其余元素依次右移,超出数组长度的部分舍弃。
这个问题的难点在于需要在原地修改数组(即不使用额外空间),并且要正确处理连续零的情况。例如输入[1,0,2,3,0,4]应该输出[1,0,0,2,3,0,0],而数组长度保持不变。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 双指针解法核心思路
2.1 正向思维与逆向思维对比
大多数初学者会首先想到正向遍历数组,遇到零就插入一个新零。但这种方法存在两个致命缺陷:
- 插入操作会导致后续元素位置变化,需要频繁移动大量元素
- 无法预先知道最终哪些元素会被挤出数组
逆向双指针法(从后向前处理)完美解决了这些问题:
- 先扫描确定哪些元素会被保留
- 再从后向前放置元素,避免频繁移动
2.2 具体算法步骤
-
第一次遍历:使用快慢指针确定最终保留的元素
- 慢指针指向最终数组位置
- 快指针遍历原数组
- 遇到零时快指针多走一步(因为零需要复制)
-
边界条件处理:
- 处理快指针刚好超出数组边界的情况
- 处理最后一个元素是零且无法完整复制的情况
-
第二次遍历:从后向前填充元素
- 快指针从数组末尾开始
- 慢指针指向最后保留的元素
- 遇到零时写入两个零
3. 代码实现与详细注释
cpp复制void duplicateZeros(vector<int>& arr) {
int n = arr.size();
int slow = 0, fast = 0;
// 第一次遍历:确定保留的元素位置
while (fast < n) {
if (arr[slow] == 0) fast++;
slow++;
fast++;
}
// 处理边界情况
slow--; fast--;
if (fast > n - 1) {
arr[n - 1] = 0;
fast -= 2;
