题目描述:
题目来源:力扣「复写零」
题目描述:给你一个长度固定的整数数组 arr,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。
注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。

算法原理:
双指针算法:先根据"异地",然后优化完成双指针下的"就地"操作。

一、先找到最后一个"复写"的数:
**双指针算法:
- 将 cur 赋值为 0,dest 赋值为 -1;先判断 cur 位置的值**
2提高cur的值决定dest向后一步还是两步
3.判断一下dest是否已经到结束位置
4.cur++
一.五. 处理一下边界情况
将n-1位置的数据改成0
cur--
dest-=2
二."从后向前"完成复写操作


处理边界情况

从后向前完成复写;

cpp
class Solution
{
public:
void duplicateZeros(vector<int>& arr)
{
//1.先找到最后一个复写的数
int cur =0; // cur 指向当前遍历的原数组位置,从下标 0 开始
int dest =-1; // dest 指向复写后数组的最后一个有效位置,初始为 -1(表示尚未确定)
int n =arr.size(); // n 为数组长度,用于判断边界
while(cur<n) // 遍历原数组,直到 cur 越界
{
if(arr[cur]) dest++; // 当前元素非 0,复写后只占 1 个位置,dest 向后移动 1 步
else dest+=2; // 当前元素为 0,复写后占 2 个位置,dest 向后移动 2 步
if(dest>=n-1) // 若 dest 已到达或超过数组最后一个下标,说明已找到最后一个被复写的数的位置
break; // 跳出循环,此时 cur 指向的就是最后一个被复写的数
cur++; // 否则继续向后遍历原数组
}
//2.处理边界情况
if(dest ==n) // 若 dest 恰好越界到 n(即最后一个复写的是 0,且它只占最后 1 个位置)
{
arr[n-1]=0; // 将数组最后一个位置直接写成 0
cur--; // cur 回退一步,跳过这个已经被处理的 0
dest-=2; // dest 回退 2 步,回到前一个有效写入位置
}
//3.从后往前复写数组
while(cur>=0) // 从最后一个被复写的数开始,从后向前遍历原数组
{
if(arr[cur]) // 当前元素非 0
{
arr[dest--]=arr[cur--]; // 直接把它写到 dest 位置,dest 和 cur 各向前移动 1 步
}
else // 当前元素为 0
{
arr[dest--]=0; // 先写一个 0 到 dest 位置,dest 向前移动 1 步
arr[dest--]=0; // 再写一个 0 到前一个位置,dest 再向前移动 1 步(复写两个 0)
cur--; // cur 向前移动 1 步,继续处理前一个元素
}
}
}
};
复杂度分析:
时间复杂度:O(n)。整个算法只对数组进行常数次线性扫描,因此时间复杂度为 O(n)。
空间复杂度:O(1) 。算法只使用了 cur、dest、n 等常数个额外变量,并且所有复写操作都在原数组 arr 上就地完成,没有借助额外的数组或容器,因此空间复杂度为 O(1)。