目录
- 题目
- 方法一:直接(暴力)求解法
- 思路分析
- 代码如下
- 方法二:双指针(快慢指针)
- 思路分析
- 代码如下
题目
这道题是来自于leetcode的一道算法题:
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。
假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:
- 更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。
- 返回 k。
示例 :
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2,_,_]
方法一:直接(暴力)求解法
所谓的暴力求解法,就是直接循环遍历整个数组,如果找到了与val相同的元素,就将这个元素后面所有的元素都向前移动,这样不仅可以覆盖到与前面的val相同的元素,还可以做到原地删除;
思路分析
代码如下
int removeElement(int* nums, int numsSize , int val)
{for (int i = 0; i < numsSize; i++){if (nums[i] == val){for (int j = i; j < numsSize - 1; j++){nums[j] = nums[j + 1];}numsSize--; //每移动一次,就有一个元素被覆盖,所以元素个数要减1i--;//每次移动,arr[j+1]的位置就要被移动到arr[j]的位置,所以我们还要再判断一次arr[j]的位置是否为val}}return numsSize; //返回元素个数
}
但是我们也可以看到,这种采取双循环暴力查找,虽然容易想到,但是时间复杂度为O( N 2 N^2 N2),空间复杂度为O(1),我们对此并不推荐;
方法二:双指针(快慢指针)
这种方法设置的比较巧妙:
思路分析
我首先将两个变量src,dest;让arr[src]和arr[dest]同时指向数组的第一个元素; 当arr[src] !=
val;我们让arr[src]的值覆盖arr[dest],即arr[dest] = arr[src],并且让src++、dest++;
当arr[src] == val时,只让src++;直到下一次arr[src] != val;重复上面的操作…
最后我们发现dest刚刚好是我们最后有效值的个数,直接返回dest:
代码如下
int removeElement(int* nums, int numsSize, int val)
{int src = 0;int dest = 0;for (int i = 0; i < numsSize; i++){if (nums[src] != val){nums[dest] = nums[src];src++;dest++;}else{src++;}}return dest;}
我们稍加优化一下,就可以减少几行代码(不管nums[src] 是否等于val,我们都要执行src++):
int removeElement(int* nums, int numsSize, int val)
{int src = 0;int dest = 0;for (int i = 0; i < numsSize; i++){if (nums[src] != val){nums[dest] = nums[src];dest++;}src++;}return dest;}
好的代码都是我们慢慢探索,慢慢的去优化的,加油,你我同在路上。
哦对了,在网上看到了一个关于这题的很搞笑的注释,分享给大家:
int removeElement(int* nums, int numsSize, int val) {int slow = 0, fast = 0; //一对夫妇,原本都是零起点while (fast < numsSize) { //但是有一个跑得快,一个跑得慢if (nums[fast] != val) { //于是跑得快的那个先去寻找共同目标nums[slow] = nums[fast]; //如果找到了,就送给跑得慢的那个slow++; //然后跑得慢的那个也就离目标近一点}fast++; //但是不管是否找得到,跑得快的那方都一直奔跑到生命的尽头}return slow; //最终留下跑得慢的一方
}
seeyou!
如果大家对此题有其他的建议,评论区我等着大家。
最后,祝26考研,一战成硕。