1.常规解法
由于队列有先进先出的特性,若使用队列存储数组元素则能维持数组元素顺序。先将数组元素一次存入队列中,再一个一个取出队列首元素从数组0下标开始放入,若首元素为0,则一次在数组中放入两个0,若首元素不为0,则只将首元素放到数组中,代码如下:
public void duplicateZeros(int[] arr) {
Queue<Integer> queue = new LinkedList<>();
for (int i = 0; i < arr.length; i++) {
queue.offer(arr[i]);
}
int count = 0;
while (count < arr.length) {
int num = queue.poll();
if (num == 0) {
arr[count] = num;
if (count + 1 >= arr.length) {
break;
}
arr[count + 1] = num;
count += 2;
} else {
arr[count++] = num;
}
}
}
2.双指针解法
若从前向后遍历整个数组,当遇到零时,必会有一个0会覆盖下一个元素,导致数组元素缺失,所以我们可以先找到复写完成的数组的最后一个元素,再从后向前遍历数组,步骤如下:
先定义两个指针left和right,left指向0下标,right指向-1下标,若left指向的元素为0,则left向后移动一位,right向后移动两位,若left下标不为0,则left和right分别向后移动一位,当left大于数组长度或right大于等于数组长度减一时,停止遍历,此时left指向的元素则为复写完成后的数组的最后一个元素,但有一种例外,当right为数组长度时,arr[right]会越界,同时left指向的元素必为0,则我们可以先将arr[right - 1]置为0,再让left减一,right减二,例子和流程图如下:
public void duplicateZeros(int[] arr) {
int left = 0;
int right = -1;
for (; left < arr.length; left++) {
if (arr[left] == 0) {
right += 2;
} else {
right++;
}
if (right >= arr.length - 1) {
break;
}
}
if (right >= arr.length) {
arr[right - 1] = 0;
left--;
right -= 2;
}
while (left >= 0 && right >= 0) {
if (arr[left] == 0) {
arr[right] = 0;
arr[right - 1] = 0;
left--;
right -= 2;
} else {
arr[right--] = arr[left--];
}
}
}