算法精选课 1089. 复写零

57 阅读2分钟

1089. 复写零 - 力扣(LeetCode)

本题用双指针+模拟的方法来解

题目要求原地修改,我们可以先试着用异地双指针的方式,最后再优化为原地双指针。

异地双指针

先来写异地的: image.png

当src不为0时,dest把src的值抄一下,然后src和dest同步++

image.png

当src为0时,dest抄一个0,然后++,再抄一个0:

image.png

然后dest和src同步++:

image.png

接下来就是接着走,最后走完是这个样子:当dest走到空就不再抄了:

image.png 现在试着合并为原地双指针:

原地双指针

image.png

src不为0,dest原地抄1,然后和src同步++。

此时src就指向0了,那么dest就要复写两个0:

image.png

问题来了,此时2已经被覆盖了,再想用2覆盖3就已经没有2了。

所以从前往后不可取,我们试着从后往前:

从后往前抄写

我们让src指向最后一个要抄的数:

image.png

此时src不为0,dest原地抄4:

image.png 然后dest和src同步--:

image.png src为0,dest抄两个0:

image.png 然后就按部就班的走,走到最后是这个样子: dest原地抄一遍1: image.png 然后和src同步--,此时下标小于-1,结束:

image.png

那么接下来的重点就是我们怎么让src刚开始指向最后一个要抄的数?

双指针求最后一个要抄写的数

让dest指向-1的位置,src指向数组开头。 我们通过src是否为0来决定dest走一步还是走两步。 image.png

此时src不为0,那么dest走一步:

image.png

接下来就按部就班的走,走到最后是这个样子:

当dest走到数组的末尾时,src就不再走了,此时src指向的就是要抄写的最后一个数。 image.png

但是这里还是有一个特殊的情况:

边界情况

当数组是这样时候:

image.png

走到最后,会走成这个样子: dest最后会走到越界的地方,所以这个越界情况需要处理一下。 image.png

处理边界情况

之所以出现这个越界情况是因为dest走到最后,src为0,dest要复写两个0,走两步造成的越界。

那我们就让它最后只复写一个0,仍然走两步走到空,但是不对越界的地址赋值0就不会报错。

image.png

code

  int src=0;
     int dest=-1;
     int n=arr.size();

     //寻找最后一个要抄写的数
     while(src<n)
     {
        if(arr[src])dest++;
        else dest+=2;
        if(dest>=n-1)break;  //>=n而不是=n的原因是有一个越界情况
        src++;
     }

     //处理边界情况
     if(dest==n)
     {
         arr[n-1]=0;
         dest-=2;
         src-=1;
     }
     


     //从后向前抄写
     while(src>=0)
     {
         if(arr[src])
     {
         arr[dest--]=arr[src--];
     }
     else
      {
         arr[dest--]=0;
         arr[dest--]=0;
         src--;
      }
   
   
    
     }