最近抽出时间leetcode刷了一些算法,突然发现很多很简单的题慢慢就引申出好几个问题,记录一下方便汇总
https://leetcode-cn.com/problems/move-zeroes/ 283 移动零
https://leetcode-cn.com/problems/remove-element/ 27题 移除元素
https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ 26题 删除排序数组中的重复项
https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii/ 80题 删除排序数组中的重复项II
这四个题目其实是一类题,感兴趣可以先去连接中看题目。
这里直接从第一个 移动零说起
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。
其实就是要去将0 移动到末尾
思路1:我们将非0元素顺序保存到一个 数组中,然后将原数组从头填充,后面补0, 空间复杂度 O(n) 不符合题意。
优化:我们如何能将 复制数组 这一步 变成一个 O(1) 的空间消耗
延伸出思路2:
我们将 非0 元素向前移动,0 向后移动,利用遍历本身的顺序性来替换掉中间存储,所以我们需要两个
指针 分别来记录 0 的下标位置,和当前迭代位置
while 换成 for 可能 更简洁,当然我们也可以通过swap 来实现
void moveZeroes(vector<int>& nums) {
// 两个指针 i,j 同时开始,i 遇到0 停了,j 后移,然后替换
int n = nums.size();
if (n < 2) return ;
int i = 0;
int j = 0;
while(j < n && i < n){
if(nums[j] != 0){
//可以用swap 代替
nums[i] = nums[j];
if(i != j){
nums[j] = 0;
}
i++;
}
j++;
}
}
基于个基本算法 我们看一下下一题 “移除元素”
其实本质就是 将 “移除0” 变为了 “移除x” + 返回新长度
移除x 判断很简单,新长度,其实就是 最后 移动到 后面的x 的所在位置,就是j
看一下代码 ,有没有发现和第一题是一模一样的
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int i =0,j=0;
int n = nums.size();
for(i=0;i<n;i++){
if(nums[i] != val){
nums[j] = nums[i];
if(i != j){
nums[i] = val;
}
j++;
}
}
return j;
}
};
删除排序数组中的重复项 也是很类似的,但是这里是排序数组,移除0 变为移除重复项
如何表述重复项: 我们找到不重复项就很容易表述重复项了 nums[i] != nums[j]
j++ 是因为 去除的是重复项 要覆盖 掉的是重复元素的第二位,换言之,你要保留下来一个 ,j+1 同理
int removeDuplicates(vector<int>& nums) {
int i=0;
int j=0;
int n=nums.size();
if (n < 2) return n;
for(i=0;i<n;i++){
if(nums[i] != nums[j]){
j++;
nums[j] = nums[i];
}
}
return j+1;
}
接着看一下升级版的 “删除排序数组中的重复项 II”
条件从 上一题的 使得每个元素最多出现一次,扩展到了“最多出现两次”
所以我们要构造出 “两次” 这个条件 然后不停的去替换,这个有点不太好理解。
我们将最多出现两次 转换为 超过两次 的元素应该向后移动,以保证最多出现两次,也就是低于两次的 不停覆盖前面就行了,只是这个覆盖位置 有可能是当前所在位置。
int removeDuplicates(vector<int>& nums) {
//[0,0,1,1,1,1,2,3,3] => [0,0,1,1,2,3,3]
//思路还是 移动 0 元素的思路
//这样思考,我们覆盖 每个位置 多余的 ( >2的 )元素,覆盖为后面元素,同样也会让后面的接着覆盖重复的
int i=1,j=1;
int n = nums.size();
if (n < 3) return n;
int count = 1;
for(i=1;i<n;i++){
if(nums[i] == nums[i-1]){
count ++;
}else{
count = 1;
}
//这个位置是一个经典, 类比 移除重复元素中 nums[i] != nums[j] 移动 0 中 的 nums[i] != 0
if(count <= 2){
nums[j] = nums[i];
j++;
}
}
return j;
}