如果觉得有所收获,不妨点个赞~
你的支持就是我创作的全部动力!
这里是原题链接:力扣
首先暴力解法:
开辟辅助数组,遍历原数组,将非零元素取出,放入新数组。
然后将新数组赋给元素组对应位置。最后将末尾元素补0
来看代码:
class Solution {
public:
void moveZeroes(vector& nums) {
vector help;
for (int i = 0; i < nums.size(); i++) {
if (nums[i]) help[i] = nums[i];
}
for (int i = 0; i < help.size();i++) {
nums[i] = help[i];
}
for (int i = help.size(); i < nums.size(); i++) {
nums[i] = 0;
}
}
};
时间复杂度O(n)问题不大。但是,Note:
You must do this in-place without making a copy of the array.
所以,这个方法pass了~不过也是一种空间换时间的思想~
现在来想想,如何优化这个方法?
优化之前,用脚指头都能想明白,这个问题不可能优化到O(1)因为我们必须遍历数组。所以首先打消这个念头。
思路很简单,不用辅助数组。
直接在原数组上操作。
用两个指针,
开始时,两个指针在同一位置,然后红色指针右移,遇到非0元素,就让蓝色指针位置元素=红色指针位置元素。然后红色指针右移,蓝色指针也右移。如果是0的话,红色指针右移,蓝色指针不动。
很抽象的过程,理解起来云里雾里的对吧。
不妨从辅助数组的角度理解,这样的优化算法,本质和辅助数组一样。
都是找到非0元素,然后把他们按原来的顺序放到数组最前面,最后把后面的所有元素用0补。
那么,蓝色指针就指向当前能够放的位置,红色指针指向准备放进去的元素。当蓝色指针指向第一个元素,红色指针指向第二个元素,发现这个元素是非0的,所以把他放进蓝色指针的位置。
之后,蓝色位置指针已经被占据了,我们让指针后移一个位置,表示后面一个可以放的位置。
红色指针也要后移,因为之前指向的元素已经放进去了。
当红色指针指向0的时候,这个元素并不需要放在最前面,因此红色指针后移,跳过这个元素,蓝色指针不动,因为当前的可以放的位置没有改变。
最后,红色指针越界了,就跳出循环。
来看看代码吧:
class Solution {
public:
void moveZeroes(vector& nums) {
int k = 0; //当前可以放的位置
for (int i = 0; i < nums.size(); i++) {
//i表示当前遍历到的位置,红色指针
if (nums[i]) nums[k++] = nums[i];
}
//当i越界之后,k表示当前可以放的最后一个位置,但是
//此时所有非0元素都已经放在最前面了,所以只需要将k位置之后的元素都补0
for (int i = k; i < nums.size(); i++) nums[i] = 0;
}
};
还有可以优化的地方哦
如果我们发现非0元素之后,交换两个指针的位置上对应的元素,就可以省掉最后一行补0的代码了。
if (nums[i]) swap(nums[k++] , nums[i]);
你可以解释出原因吗?
针对特殊的用例,还有优化的余地。
如果数组全是非零元素,那么 两个指针一直指向同一个位置
这时候,就一直在和自己交换位置。
如何优化呢?
if (nums[i] && k!=i) swap(nums[k++] , nums[i]);
else if (k == i) k++;
我这样写很奇怪吧。
换个写法:
if (nums[i])
{
if(k!=i)
swap(nums[k++], nums[i]);
else /*(k == i)*/ k++;
}
不妨自己思考一下,为啥这样写。这其中的逻辑关系是如何。
如果看懂了,不妨去试试力扣leetcode-cn.com
思路非常类似,代码都很一样哦。
class Solution {
public:
int removeElement(vector& nums, int val) {
int i=0;
for(int j=0;j
if(nums[j]!=val){
if(i!=j) nums[i++]=nums[j];
else i++;
}
}
return i;
}
};
还有这个题:力扣leetcode-cn.com
int removeDuplicates(vector& nums) {
if(nums.size()<2) return nums.size();
int j=0;
for(int i=1;i
if(nums[j]!=nums[i]){
nums[++j]=nums[i];
}
}
return ++j;
}
超级简洁的代码。
其中: nums[++j]=nums[i]; 真的是很精髓了。
原理就是,留出同类的第一个元素不变,改变这类元素后面的元素。
很难解释,此中有真意,欲辨已忘言。