每日一题:LeetCode-1089. 复写零

简介: 每日一题:LeetCode-1089. 复写零

每日一题系列(day 09)

前言:

🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈

   🔎🔎如果说代码有灵魂,那么它的灵魂一定是👉👉算法👈👈,因此,想要写出💚优美的程序💚,核心算法是必不可少的,少年,你渴望力量吗😆😆,想掌握程序的灵魂吗❓❗️那么就必须踏上这样一条漫长的道路🏇🏇,我们要做的,就是斩妖除魔💥💥,打怪升级!💪💪当然切记不可😈走火入魔😈,每日打怪,拾取经验,终能成圣🙏🙏!开启我们今天的斩妖之旅吧!✈️✈️


题目:

  给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。

  注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西

示例:

提示:

  • 1 <= arr.length <= 104
  • 0 <= arr[i] <= 9

思路:

  如果自己尝试写的时候发现其实并不简单,虽然被力扣标为简单。题目说遇到0要复写,把0后面的元素全部向后移动一位,留下一个位置给复写的0,而且只能在本数组内操作,不能扩容。在上到题目中我们说了,这种类似的问题都是可以使用双指针来解决。如何使用双指针就成了问题。

  虽然这题是让我们在原数组操作,但是我们不妨先开辟一个数组,cur指针指向原数组,dest指针指向新数组,只要cur不为0,dest就复制cur的值,如果cur为0,dest就移动两步,且每一步都写为0。

  这个时候我们发现dest指针所在数组与测试用例的结果相同,说明我们的思路是正确的,但是题目要求我们是原地操作。

  首如果我们按照常规的思路,首先设置cur指针用来遍历数组,同时表示dest指针走几步,因为开始不知道dest走几步,所以将dest的值设置为-1。

  既然我们从左向右的双指针不得行,我们可以考虑从右向左来进行复写操作,但是我们要想保证复写的正确性,还需要知道正向复写最后一个复写的元素,这样才能从后向前复写。

  其实我们在最开始假设有新数组来复写的操作,我们可以看到最后一个复写的值为4,最后dest和cur又都多走了一步,我们仅需将条件控制为:

dest <= arr.size() - 1;

即可,这样cur就会指向最后一个需要复写的元素了,dest也正好指向最后一个元素。而对于原地操作,我们仅仅需要找到cur的位置和dest的位置就行,所以在找位置的情况我们不需要复写,就可以在同一个数组操作了。

  这个时候,我们的cur的位置就是最后需要复写的位置,而dest正是我们需要复写的最后一个元素。

  找到这个元素之后,我们就可进行从后往前的复写操作了,当arr[cur]不为0的时候,dest向前移动一位并且复写这个数,cur–。如果cur为0,dest就向前走两位,每位复写为0,cur–。即可

代码实现:

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        int cur = 0;
        int dest = -1;
        while(cur < arr.size())
        {
            if(arr[cur]) 
            dest++;
            else
            dest += 2;
            if(dest >= arr.size() - 1) break;
            cur++;
        }
        while(dest > -1)
        {
            if(arr[cur]) arr[dest--] = arr[cur--];//cur不为0拷贝一次
            else 
            {
                arr[dest--] = 0;//cur为0复写两次
                arr[dest--] = 0;
                cur--;
            }
        }
    }
};

但是这个时候我们运行的时候却发现:

出现了这么的错误,我们可以看到他给我们的报错的测试用例:

  我们不妨画图看一下问题在哪?

  原来是我们的dest指针越界了,在我们复写的时候这种情况会在数组外边越界访问了,这种情况是造成的原因是最后一个复写元素为0的原因。

  如果不考虑越界的情况继续复写一步操作我们会发现:

  所以其实我们仅仅需要控制住边界条件,复写时将:

arr[arr.size() - 1] = 0;

即可。所以我们可以这样改:

代码实现:

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        int cur = 0;
        int dest = -1;
        while(cur < arr.size())
        {
            if(arr[cur]) 
            dest++;
            else
            dest += 2;
            if(dest >= arr.size() - 1) break;
            cur++;
        }
        if(dest == arr.size())//加上边界判断即可
        {
            arr[arr.size() - 1] = 0;
            dest -= 2;
            cur--;
        }
        while(dest > -1)
        {
            if(arr[cur]) arr[dest--] = arr[cur--];
            else 
            {
                arr[dest--] = 0;
                arr[dest--] = 0;
                cur--;
            }
        }
    }
};


  这样我们就可以通过了,这题虽然被标记为简单,但是我感觉却一点也不简单(主要是太菜),需要注意的是双指针的灵活运用,以及边界情况的考量要到位。

相关文章
LeetCode每日一题——1089. 复写零
给你一个长度固定的整数数组 arr,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。
97 0
|
6天前
|
算法 C++
【刷题】Leetcode 1609.奇偶树
这道题是我目前做过最难的题,虽然没有一遍做出来,但是参考大佬的代码,慢慢啃的感觉的真的很好。刷题继续!!!!!!
9 0
|
6天前
|
算法 索引
【刷题】滑动窗口精通 — Leetcode 30. 串联所有单词的子串 | Leetcode 76. 最小覆盖子串
经过这两道题目的书写,相信大家一定深刻认识到了滑动窗口的使用方法!!! 下面请大家继续刷题吧!!!
13 0
|
6天前
|
算法
【刷题】 leetcode 面试题 08.05.递归乘法
递归算法是一种在计算机科学和数学中广泛应用的解决问题的方法,其基本思想是利用问题的自我相似性,即将一个大问题分解为一个或多个相同或相似的小问题来解决。递归算法的核心在于函数(或过程)能够直接或间接地调用自身来求解问题的不同部分,直到达到基本情况(也称为基础案例或终止条件),这时可以直接得出答案而不必再进行递归调用。
25 4
【刷题】 leetcode 面试题 08.05.递归乘法
|
6天前
|
存储 算法 安全
【刷题】 leetcode 面试题 01.06 字符串压缩
来看效果: 非常好!!!过啦!!!
27 5
【刷题】 leetcode 面试题 01.06 字符串压缩
|
6天前
|
存储 算法 测试技术
|
6天前
|
算法 C语言 C++
|
6天前
|
存储 算法 C语言
C语言刷题~Leetcode与牛客网简单题
C语言刷题~Leetcode与牛客网简单题
|
6天前
刷题之Leetcode160题(超级详细)
刷题之Leetcode160题(超级详细)
15 0