题目1:283.移动零
题目分析:
将数组分为两个区间,左边为非零区间,右边为零区间。
数组划分,数组分块类问题。- 优先双指针解决
思路1:删除+尾插
C语言来实现的话就是,遍历遇到零,就后面的数向前覆盖,在补一个零。这里C++其实也是相同的思路,erase删除,push_back尾插。count的作用就是控制循环次数,免得重复操作。
代码实现:
class Solution { public: void moveZeroes(vector<int>& nums) { auto it=nums.begin(); int count=0; for(size_t i=0;i<nums.size()-count;) { if(nums[i]==0) { count++; nums.erase(it+i); nums.push_back(0); }else i++; } return ; } };
思路2:双指针
将数据分为三个区域:非零区域,零区域,未处理区域。
代码实现:
class Solution { public: void moveZeroes(vector<int>& nums) { int dest=-1,cur=0; while(cur<nums.size()) { if(nums[cur]!=0) swap(nums[cur],nums[++dest]); cur++; } return; } };
题目2:1089.复写零
题目分析:
思路1:暴力解法
遍历,是零就插入一个零,注意i需要加1,防止再次访问已处理过的零,插入后再尾删即可。
代码实现:
class Solution { public: void duplicateZeros(vector<int>& arr) { for(size_t i=0;i<arr.size();i++) { if(arr[i]==0) { auto it=arr.begin(); arr.insert(it+i,1,0); arr.pop_back(); i++; } } return; } };
思路2:双指针
如果是异地操作相当的简单,但我们可以借鉴思路。
我们不能从前往后写,因为dest指针会跑到cur后面,导致后面未处理数据被覆盖。
所以我们从后往前写,但要去找cur的最后一个复写位置。所以还需要从前往后来一次双指针找位置。
但是位置的时候又会引发一个问题:cur最后一个位置是0,会导致dest位置越界(这一点需要考虑)
然后就可以开始复写了。
代码实现:
class Solution { public: void duplicateZeros(vector<int>& arr) { int cur = 0, dest = -1; //1.找位置 while (cur < arr.size()) { if (arr[cur]) dest++; else dest += 2; if (dest >= arr.size() - 1) break; cur++; } //2.处理边界值 if (dest == arr.size()) { arr[arr.size() - 1] = 0; cur--; dest -= 2; } //3.复写操作 while (cur >= 0) { if (arr[cur] == 0) { arr[dest--] = 0; arr[dest--] = 0; cur--; } else { arr[dest--] = arr[cur--]; } } } };