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