力扣刷题
代码随想录数组 3.移除元素
力扣27. 移除元素
方法一:暴力解决法
1. 思路
两层嵌套循环遍历数组,内层循环主要是当第一层循环遍历到的元素等于要移除的元素的值的时候,其后的元素依次向前挪动一个位置(覆盖要删除的元素的位置)
编译出错:cannot assign a value to final variable length
为什么报错?因为Java中数组是不允许被修改长度的!这是Java安全性的体现之一。
数组的内存是连续分配的,当我们增加数组长度时,就可能导致别的变量被覆盖;而减少长度的话,可能会突然空出来一个内存空间。
2. 正确解题代码
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
class Solution {
public int removeElement(int[] nums, int val) {
int size = nums.length; //定义成一个变量,但它并不是数组的实际长度
for(int i = 0; i < size; i++){
if(nums[i] == val){
for(int j = i; j < size - 1; j++){
nums[j] = nums[j+1];
}
size--; //这是我们认为的数组移除某元素之后的长度(但数组的实际长度并没有变化)
i--; //当前的元素已经被后一个元素所替代,又因为等会要i++,所以应该先向前挪动一个
}
}
return size;
}
}
方法二:同向双指针(快慢指针)
class Solution {
public int removeElement(int[] nums, int val) {
//同向双指针
//快指针是遍历数组的时候找值不为val的元素,
//慢指针是用来得到新的数组长度(覆盖要移除的元素的位置)
int slowIndex = 0;
for(int fastIndex = 0; fastIndex < nums.length; fastIndex++){
if(nums[fastIndex] != val){
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
}
方法三:相向双指针
class Solution {
public int removeElement(int[] nums, int val) {
//相向双指针
//左指针是用来得到新的数组长度(覆盖要移除的元素的位置),
//右指针是从右边开始向左边遍历找值不为val的元素
int rightIndex = nums.length - 1;
int leftIndex = 0;
while(rightIndex >= 0 && nums[rightIndex] == val) rightIndex--;
while(leftIndex <= rightIndex){
if(nums[leftIndex] == val){ //当左指针指向的元素等于要移除的值,则用右指针的元素值进行覆盖
nums[leftIndex] = nums[rightIndex--];
}
leftIndex++; //左指针向前继续挪动
while(rightIndex >= 0 && nums[rightIndex] == val) rightIndex--;//右指针继续寻找下一个值不为val的元素
}
return leftIndex;
}
}
同向与相向的对比:
- 同向双指针最后元素的相对位置没有发生变化,而相向双指针最后的元素相对位置可能发生变化,即数组的相对顺序发生了改变
- 同向双指针和相向双指针两者的时间复杂度及空间复杂度都是一样的
- 时间复杂度:O(n)
- 空间复杂度:O(1)