一、题目
给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
二、示例
示例 1:
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度2,并且 nums 中的前两个元素均为2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为2 ,而nums = [2,2,3,3]或nums = [2,2,0,0],也会被视作正确答案。
示例 2:
输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度5, 并且nums中的前五个元素为0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
三、要求
0 <= nums.length <= 100
0 <= nums[i] <= 50
0 <= val <= 100
四、解答
1.思路
由于在需要在原地移出等于val的元素,就是需要将数组前面等于val的元素移动到数组末尾。所以可以使用双指针,i指向数组首元素,j指向数组末元素,直接遍历数组,如果val[i]==val
,再从后遍历数组,找到val[j]!=val
,然后交换val[i]和val[j]
的值,i++ ,j- -,当i==j时,结束从前往后后的遍历,返回计数器len.
改进思路:
上面方法时间复杂度太大了,我们使用了双层嵌套循环。我们为什么要从尾部也遍历一次呢?因为我们担心尾部交换过来的元素等于val,因为上面我们没次交换过后从头部严格执行了i++,如果我们在头部比较不同之后,再i++呢?那么我们的尾部可以直接交换,而无需判断不等于val,因为头部会判断交换过的值不等于val,再i++。
2.代码
java代码如下(示例):
class Solution {
public int removeElement(int[] nums, int val) {
int len=0;
int srclen=nums.length;
int j=srclen-1;
for(int i=0;i<srclen ;i++){
if (nums[i]==val){
len++;
while(j>i){
if (nums[j]!=val){
int tag;
tag=nums[i];
nums[i]=nums[j];
nums[j]=tag;
j--;
break;
}else{
j--;
len++;
}
}
}
if(i==j){
break;
}
}
return srclen-len;
}
}
改进后的代码:
class Solution {
public int removeElement(int[] nums, int val) {
int i=0,j=nums.length-1;
while(i<=j){
if (nums[i]==val){
nums[i] = nums[i]^nums[j];
nums[j] = nums[i]^nums[j];
nums[i] = nums[i]^nums[j];
j--;
}
else{
i++;
}
}
return j+1;
}
}