
复写零这道题是让在原数组修改,如果从前向后遍历,后面的元素会被覆盖,所以我们要找到被复写的最后一个元素,然后从后往前复写。运用双指针+逆向填充
定义两个指针:cur遍历原数组,pre模拟复写后的数组指针;
cur==0时,pre向后移动两位,cur!=0时,pre向后移动两位(因为要复写0);
当pre>=n-1时,停止遍历,这时,cur指的就是要复写的最后一个元素

边界情况:如下面这种情况,pre == n时,说明要复写的最后一个元素是0,这里单独处理
将数组最后一位改为0,也就是n==0;
cur向前移动一位,pre向前移动两位;

从cur向前遍历,cur != 0时,就让arr[pre] == arr[cur];
cur == 0时,就让pre和pre-1位置的数都改为0,然后继续向前复写。

class Solution { public void duplicateZeros(int[] arr) { int cur = 0, pre = -1, n = arr.length; //1.找到要复写的最后一个元素 while(cur < n){ if(arr[cur] == 0){ pre += 2; }else{ pre++; } if(pre >= n-1){ break; } cur++; } //处理边界情况 if(pre == n){ arr[n-1] = 0; cur--; pre -= 2; } //开始从后向前复写 while(cur >= 0){ if(arr[cur] != 0){ arr[pre--] = arr[cur--]; }else{ arr[pre--] = 0; arr[pre--] = 0; cur--; } } } }
时间复杂度O(n):只需要遍历数组两次,第一次定位边界,第二次逆向填充;
空间复杂度O(1):使用的原数组,没有额外空间
本解法通过双指针先定位复写边界,再逆向填充数组,既避免了正向遍历的元素覆盖问题,又实现了 O(n) 线性时间复杂度与 O(1) 常数空间复杂度的最优表现。其中“先确定边界、再逆向操作”的思路,是解决数组原地修改类问题的关键技巧,具有较强的通用性与实用性。