leetcode数组汇总_LeetCode经典问题总结:数组的移动

本文探讨了如何在不使用额外空间的情况下,通过双指针技术优化数组中零元素的移动过程。首先介绍了暴力解法,即创建辅助数组,然后阐述了原地修改数组的优化算法,通过两个指针实现非零元素前移并填充零。文章还提到了特殊情况的处理,如全非零数组的情况,并提供了相关LeetCode题目以供实践。
摘要由CSDN通过智能技术生成

如果觉得有所收获,不妨点个赞~

你的支持就是我创作的全部动力!

这里是原题链接:力扣

首先暴力解法:

开辟辅助数组,遍历原数组,将非零元素取出,放入新数组。

然后将新数组赋给元素组对应位置。最后将末尾元素补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]; 真的是很精髓了。

原理就是,留出同类的第一个元素不变,改变这类元素后面的元素。

很难解释,此中有真意,欲辨已忘言。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值