给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。
- 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
- 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
- 示例 1:
- 给定 nums = [3,2,2,3], val = 3,
- 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
- 你不需要考虑数组中超出新长度后面的元素。
1.拷贝覆盖
主要思路:定义一个变量,对不重复的值计数。for循环完成。
存在的问题 就是值可以计算出当前不相同值,数组的值是不符合要求的。
这种思路在移除元素较多时更适合使用,最极端的情况是全部元素都需要移除,遍历一遍结束即可
时间复杂度:O(n) 空间复杂度O(1)
public static int removeElement3(int [] nums,int val){
int count = 0;
for (int num:nums) {
if (num!=val){
nums[count++] = num;
}
}
return count;
}
2.交换移除
主要思路:用一个变量去记录数组的长度,然后处理两种情况,一种是当前的值等于val 就将数组中最后的值赋值给当前相同的值,m 用来不断减少数组的长度。否则的话 是另一种情况 如果不相等 直接i++ 判断下一个就可以。
这种思路在移除元素较少时更适合使用,最极端的情况是没有元素需要移除,遍历一遍结束即可
时间复杂度:O(n),空间复杂度:O(1)
public static int removeElement4(int [] nums,int val){
int m = nums.length;
for (int i = 0; i < m; ) {//注意for 这里不能i++ i是用来确认哪些数据不是要寻找的
if (nums[i] == val){
nums[i] = nums[m-1];
m--;
}else {
i++;
}
}
return m;
}
3.双指针
实现思路:一个快指针 一个慢指针。用快指针来判断是否相等 不相等赋值给慢指针,慢指针的作用是来定位前面如果有重复的直接跳过去。
时间复杂度:o(n)
空间复杂度:o(1)
public static int removeElement5(int [] nums,int val){
int i = 0;
for (int j = 0; j < nums.length; j++) {
if (nums[j]!=val){
nums[i] = nums[j];
i++;//加1
}
//如果相等 不做 等待下标i来进行覆盖
}
return i;
}
4.双指针 —当要删除的元素很少时
实现思路:通过快慢指针 在一种比较极端的情况下。nums[1,2,3,5,4] val = 4 在最后才可以找到需要删除的元素,虽然nums中的值没有改变,但是通过m-- 停止了循环 i=4。
当我们遇到 nums[i] = valnums[i]=val 时,我们可以将当前元素与最后一个元素进行交换,并释放最后一个元素。这实际上使数组的大小减少了 1。
时间复杂度:O(n)
空间复杂度:O(1)
public static int removeElement6(int [] nums,int val){
int i = 0;
int m = nums.length;
while (i<m){
if (nums[i] == val){//相当的话 直接将快指针元素赋值给慢指针
nums[i] = nums[m-1];
m--;
}else {
i++;//不相等 直接跳过
}
}
return i++;
}