Problem: 1089. 复写零
文章目录
- 题目解析
- 算法原理分析
- 找到最后一个复写的位置
- 从后往前进行复写操作
- 代码展示
题目解析
首先我们来分析一下本题的题目意思
- 可以看到题目中给到了一个数组,意思是让我们将数组中的零元素都复写一遍,然后将其余的元素向后平移
- 光就上面这样来看还是不太形象,我们通过画图来分析一下,通过下图我们可以看到,凡是0的都复写了两遍,凡不是0的都复写了一遍
- 但是呢题目中很明显地讲到只能让我们在数组上进行就地操作,但是就我们上面的操作而言则是在另外开辟了一块数组的空间
那在下面我们就去考虑一下在数组原地的操作
- 可以看到在下面我使用到了双指针的操作,若是
cur
遍历到0的话就进行两次的复写操作,不过呢大家可以看到在第一次的复写操作完成之后,【2】被覆盖了,但是这个【2】是我们需要的,那也就造成了一定的问题
💬 那么反应快的同学可以意识到,如果要进行覆盖操作的话就需要 从后往前 进行遍历操作才可以
算法原理分析
好,接下去呢我们就来分析一下解决本题的思路
找到最后一个复写的位置
- 上面说到是要从后往前开始做复写操作,那么第一步我们所要做的就是找到最后一个复写的位置,即让这个
dest
指向最后的0
那要怎么去找呢?(头一次尝试幻灯片≧ ﹏ ≦)
可以分为以下几步:
- 判断cur位置的值,决定dest走一步还是两步
- 判断dest是否到达末尾,决定cur是否++
<,,,,,,>
但是呢,就上面这样的逻辑去走的话其实是不对的,因为我们还未考虑到特殊的边界情况
- 即下面的这种情况,当测试用例的倒数第二个数为0的时候,此时
dest
又刚好到这个位置,那么就需要向后移动两步,此时就造成了越界问题
所以此时我们应该要考虑处理一下这个边界问题
- 因为倒数第二个数为0,那么对其进行复写操作的话,最后一个也是0,我们将其做一个修改即可,不过呢两个指针
cur
和dest
也需要去做一个变化,cur
前移一位即可,dest
因为做了复写操作,所以需要前移两位
从后往前进行复写操作
上面呢,我们已经找到了需要复写的最后一个位置,那接下去我们就要正式开始复写操作了
- 这一块的话就不做动画演示了,读者可以试着自己去手动模拟一下,也就是从我们上面所找到的
cur
位置开始,慢慢地向前遍历然后去做复写操作即可,将数一一地复写到dest
所在的位置,如果arr[cur]
为0的话,那我们就需要考虑复写两次了
代码展示
最后来展示一下整体的代码
class Solution {
public:
void duplicateZeros(vector<int>& arr) {
// 1.找到复写的最后一个位置
// (1) 判断cur位置的值,决定dest走一步还是两步
// (2) 判断dest是否到达末尾,决定cur是否++
int dest = -1;
int cur = 0;
int sz = arr.size();
while(dest < sz)
{
if(arr[cur]) dest++;
else dest += 2;
if(dest >= sz - 1)
break;
cur++;
}
// 2.判断边界的情况
if(dest == sz)
{
arr[dest - 1] = 0;
cur--;
dest -= 2;
}
// 3.从右往左复写0
while(cur >= 0)
{
if(arr[cur]) arr[dest--] = arr[cur--];
else
{
arr[dest--] = 0;
arr[dest--] = 0;
cur--;
}
}
}
};
下面是运行后的结果