📝前言说明:
- 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录,按专题划分
- 每题主要记录:1,本人解法 + 本人屎山代码;2,优质解法 + 优质代码;3,精益求精,更好的解法和独特的思想(如果有的话)
- 文章中的理解仅为个人理解。如有错误,感谢纠错
🎬个人简介:努力学习ing
📋本专栏:C++刷题专栏
📋其他专栏:C语言入门基础,python入门基础,C++学习笔记,Linux
🎀CSDN主页 愚润泽
视频
- 293. 移动零
- 个人解
- 优质解
- 1089. 复写零
- 个人解
- 优质解:
293. 移动零
个人解
思路:
用时:15:16,(真是没救了,写成这样)
屎山代码:通过
class Solution {
public:void moveZeroes(vector<int>& nums) {int n = nums.size();int slow = 0;int fast = 1;while(slow < n && fast < n){while(slow < n && nums[slow] != 0){slow++;}while(fast < n && (fast < slow || nums[fast] == 0)){fast++;}if(slow < n && fast < n){swap(nums[slow], nums[fast]);slow++;fast++;}}}
};
时间复杂度:O(n)
空间复杂度:O(1)
优质解
思路:整个数组可以划分成:已排序区[0, slow]
+ 零区[ slow + 1, fast )
+ 待排序区[fast, n-1]
我屎山代码的问题:我的slow
和fast
是分别移动的,后续还需要自己维护fast > slow
优质解法:
slow
指针始终指向已排序区的最后一个元素,slow
不主动移动,只在交换时移动,这样就可以始终用来标识已排序区的位置。- 用
fast
指针遍历数组,当fast != 0
时,和slow + 1
位置的0
交换。
class Solution {
public:void moveZeroes(vector<int>& nums) {int slow = -1, fast = 0;for(fast = 0; fast < nums.size(); fast++){if(nums[fast]){swap(nums[fast], nums[slow + 1]);slow++;}}}
};
时间复杂度:O(n)
空间复杂度:O(1)
1089. 复写零
个人解
思路:一个指针在前,一个指针在后,前指针遇到0
要复写的时候,通过后指针,把复写位置后的元素都往后移动一位,腾出空间。
用时:17:21,
屎山代码:通过
class Solution {
public:void duplicateZeros(vector<int>& arr) {int n = arr.size();int slow = 0, fast = n - 1;while(slow < n - 1){if(arr[slow]){slow++;}else{slow++;for(fast = n - 1; slow < fast; fast--){arr[fast] = arr[fast - 1];}arr[slow] = 0;slow++;}}}
};
时间复杂度:O( n 2 n^2 n2)
空间复杂度:O(1)
优质解:
首先,我们先思考,如果不是就地操作的解法:
创建一个新的数组,然后一个指针cur
指向原数组,一个指针dest
指向新数组,dest
根据cur
的值不断进行复写操作。
那换成就地操作呢?
如果直接这么操作,那dest
复写两次的时候就会覆盖还没有复写的值。
那能不能从后往前进行复写操作?
答案是可以的,问题是要先找到最后一个复写的数。
最后一个复写的数由什么决定?
如果我们看题不仔细,不认真思考的话就会简单认为:0
的个数直接决定后面几个数会被移出数组外,如:若有3个0,那么倒数第4个数就是最后一个复写的数。(因为后3个数的位置 → 被前面复写的0
个替代了)
但其实不然,因为:0
有可能被移动出去
所以,重点又变成了,如何找最后一个要复写的数的位置。
方法:我们先模拟一遍复写的过程但是不复写,就可以让cur
定位到最后一个要复写的元素,dest
指向从后往前复写的第一个要复写的开始位置。
步骤:
cur
指向当前要复写的元素,遍历数组,dest
指向已经复写完的位置(的最后一个)- 当
arr[cur] == 0
,dest
移动两步,否则为一步 - 判断
dest
是否到达结束位置,达到了就提前退出循环。
注意点1:在本次循环中的cur不能移动,因为cur指向的是要复写的,如果移动了就到了下一个没有复写的位置。
注意点2:会有在数组外复写的情况:这种情况是在dest == n-1
的时候还要复写两个0
,解决方法:只需要让arr[n-1] = 0
,dest -= 2
,cur -= 1
就行,因为这种情况下已确定最后一位写的是0
文字叙述晦涩难懂,建议画图
代码:
class Solution {
public:void duplicateZeros(vector<int>& arr) {int cur = 0, dest = -1, n = arr.size(); // dest指向复写完的最后一个位置while(cur < n) {if(arr[cur]) dest++; else dest += 2;if(dest >= n-1) break; // dest = n-1 代表已经写完最后一个位置了cur++; // cur指向的元素代表要复写的元素}if(dest == n) // 代表在数组外面写了{arr[n-1] = 0;dest -= 2;cur -= 1;}while(cur >= 0){if(arr[cur]) arr[dest--] = arr[cur--];else{arr[dest--] = 0;arr[dest--] = 0;cur--;}}}
};
时间复杂度:O(n)
空间复杂度:O(1)
🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!