代码随想录算法训练营第一天 || (双指针)27.移除元素 26.删除有序数组中的重复项 283.移动零 977.有序数组的平方
代码随想录算法训练营第一天 || (双指针)27.移除元素 26.删除有序数组中的重复项 283.移动零
- 27.移除元素
- 暴力方法
- 同向双指针双指针
- 自己AC的解答
- 卡哥的讲解
- 26.删除有序数组中的重复项
- 同向双指针
- 283.移动零
- 自己解答
- 灵神做法(同向双指针+交换)
- 977.有序数组的平方
- 暴力排序
- 相向双指针
27.移除元素
文档讲解:移除元素
视频讲解:数组中移除元素并不容易
状态:听完思路,自己成功实现代码
暴力方法
数组中移除元素是通过覆盖的方式进行的,而不是直接删除
本题,我们先采用暴力方法进行解答:
class Solution {
public:int removeElement(vector<int>& nums, int val) {int n = nums.size();for (int i = 0; i < n; i++) {if (nums[i] == val) {for (int j = i + 1; j < n; j++) {nums[j - 1] = nums[j];}i--;n--;}}return n;}
};
暴力方法时间复杂度是O(n^2),空间复杂度是O(1)
同向双指针双指针
就是用一层循环来解决暴力法两层循环
自己AC的解答
class Solution {
public:int removeElement(vector<int>& nums, int val) {int n = nums.size();int fast, slow = 0;for (fast = 0; fast < n; fast++) {if (nums[fast] == val) {continue;}nums[slow++] = nums[fast];}return slow;}
};
遇到的问题:slow要在前面初始化,否则会给出任意值,造成超出数组大小
卡哥的讲解
首先我们定义两个指针 fast
和 slow
快指针的作用:寻找新数组的元素,新数组就是不含有目标元素的数组
慢指针的作用:指向更新 新数组下标的位置
class Solution {
public:int removeElement(vector<int>& nums, int val) {int n = nums.size();int slow = 0, fast = 0;for (fast = 0; fast < n; fast++) {if (nums[fast] != val) {nums[slow ++] = nums[fast];}}return slow;}
};
这样实现代码比我实现的要简单,直接把符合的元素放入slow的位置,而我的方法失去剔除不符合的元素,然后再放入。
26.删除有序数组中的重复项
状态:没做出来,想复杂了,想用映射来做,定义一个数组,出现过的元素,数组++,如果>1就是重复出现。
同向双指针
这道题我忽略了一个点,就是这个数组是排好序的,我们只需要判断nums[i]
与nums[i - 1]
是否相等即可。
class Solution {
public:int removeDuplicates(vector<int>& nums) {int slow = 1;int n = nums.size();for (int fast = 1; fast < n; fast ++) {if (nums[fast - 1] != nums[fast]) {nums[slow ++] = nums[fast];}}return slow;}
};
注意: 第一个元素一定是保留的,fast
从第二个元素开始,所以slow
也是从1开始。
本题与上一题的区别就是,上一题是判断是否与val
相等,本题是判断数组中这个元素是否与上一个元素相等,不要想复杂。
283.移动零
状态:自己做出来了,但有点复杂
自己解答
class Solution {
public:void moveZeroes(vector<int>& nums) {int fast = 0, slow = 0;int n = nums.size();for (fast = 0; fast < n; fast ++) {if (nums[fast] != 0) nums[slow ++] = nums[fast];}for (int i = slow; i < n; i ++) {nums[i] = 0;}}
};
我的思路是,把不是0的元素全都提出来,然后最后再补0
灵神做法(同向双指针+交换)
思路:同向双指针 + 交换
流程:
首先从左到右遍历nums[i]
,并设置另一个指针 i0(初始值为0)
初始当nums[i] != 0
时,i0 与 i 一同移动
每当nums[i] = 0
时,保持 i0 不移动,也就是 i0 指向0的时候停下来
一直到nums[i] != 0
时,交换 nums[i] 和 nums[i0]
这样就做到能把所有0都放到后面,并且保持非0元素顺序不变
代码如下:
class Solution {
public:void moveZeroes(vector<int>& nums) {int i0 = 0;int n = nums.size();for (int i = 0; i < n; i++) {if (nums[i]) {swap(nums[i], nums[i0]);i0++;}}}
};
或者可以使用 范围for循环,注意这里要私用 引用&
class Solution {
public:void moveZeroes(vector<int>& nums) {int i0 = 0;int n = nums.size();for (int &x : nums) {if (x) {swap (x, nums[i0]);i0 ++;}}
};
977.有序数组的平方
文档讲解代码随想录有序数组的平方
视频讲解双指针经典题目
状态:没想到用相向双指针,用同向双指针没有做出来
暴力排序
class Solution {
public:vector<int> sortedSquares(vector<int>& nums) {int n = nums.size();for (int i = 0; i < n; i++) {nums[i] = nums[i] * nums[i];}sort(nums.begin(), nums.end());return nums;}
};
sort()
的底层实现是快速排序,时间复杂度是O(nlogn)
,不符合题目要求
相向双指针
本道题数组是有序的,只不过可能存在负数,因为数组有序,所以平方后的最大值要么是第一个数,要么是最后一个数。
我们采用相向双指针,如果第一个数平方大于最后一个数平方,就把第一个数的平方存放入新的数组中,注意这里是从大到小存放。
class Solution {
public:vector<int> sortedSquares(vector<int>& nums) {int n = nums.size();int k = n - 1;vector<int> res(n);for (int i = 0, j = k; i <= j; ) { // 注意这里要i <= j,因为最后要处理两个元素if (nums[i] * nums[i] > nums[j] * nums[j]) {res[k --] = nums[i] * nums[i ++];} else {res[k --] = nums[j] * nums[j --];}}return res;}
};