LeetCode刷题-- 删除元素
LeetCode刷题--删除元素
一、题目
给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并「原地」修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1:
给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
你不需要考虑数组中超出新长度后面的元素。示例 2:
给定 nums = [0,1,2,2,3,0,4,2], val = 2,
函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。「你不需要考虑数组中超出新长度后面的元素。」
二、题解
本题的关键是通过将要删除的元素的后面的元素向前移动,去覆盖掉要删除的元素,并且将要删除的元素每次都移动在最后面,
有两种解决办法:
第一种是:暴力法 ,通过两个for循环,第1个for循环负责遍历数组,第二个for循环负责更新数组。
第二种是:
双指针法(快慢指针法)
,通过一个快指针和慢指针在一个for循环下完成两个for循环的工作:
- 循环时,快慢指针一起移动
- 查到了值,快指针继续移动,慢指针暂停移动一次
- 直到快指针指向数组末尾 返回慢指针的位置,就是数组中剩余的元素个数
三、代码
public class _02_移除元素 {
/**
* 1. 暴力解法: 时间负载度O(n^2) 空间复杂度O(1)
* @param nums
* @param val
* @return
*/
public static int removeElement1(int[] nums, int val) {
int len = nums.length;
for(int i = 0; i < len; i++){
if(val == nums[i]){
for(int j = i+1; j < len; j ++){
nums[j-1] = nums[j];
}
i--;
len--;
}
}
return len;
}
/**
* 双指针法
* 循环时,快慢指针一起移动
* 查到了值,快指针继续移动,慢指针暂停移动一次
* 直到快指针指向数组末尾 返回慢指针的位置。
* @param nums
* @param val
* @return
*/
public static int removeElement2(int[] nums, int val) {
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
if(val != nums[fastIndex] ){ // 如果不等,才是覆盖,移动,否则只有快指针移动
nums[slowIndex ++] = nums[fastIndex];
// 这一步可以分解成两步比较好理解:
// 1. 先赋值: nums[slowIndex] = nums[fastIndex];
// 2. 慢指针移动: slowIndex ++;
// 3. 快指针移动: for循环中的fastIndex ++
}
}
return slowIndex;
}
public static void main(String[] args) {
int [] nums = {3,2,2,1,1,3};
int val = 3;
System.out.println(removeElement2(nums, val));
}
}
四、时间负载度和空间复杂度
暴力法: 时间复杂度O(n^2) ,空间复杂度O(1)
双指针法:时间复杂度O(n) ,空间复杂度O(1)