problem
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
solution
思路过程
- 一想到的就是把数组中的数往前覆盖,不行,这个想法没有想通
- 先遍历一次,把等于val的值置为0,再遍历一次,把0的位置填满
- 假如有k个0,那么数组后面肯定向前遍历k个位置就可以了
代码
class Solution {
public int removeElement(int[] nums, int val) {
int k=0;// 记录与val相等的个数
int n=nums.length;
for(int i=0;i<n;++i){
if(nums[i]==val){
k++;
nums[i]=-1;
}
}
int j=n-1;
for(int i=0;i<n-k;++i){
if(nums[i]==-1){
while(j>=n-k){
if(nums[j]!=-1){
nums[i]=nums[j];
j--;
break;
}
j--;
}
}
}
return n-k;
}
}
提升
- 可不可以一次遍历就完成呢?
- 一个指向头(l),一个指向尾(r),头遇到相等值就去把尾巴不是相等值的替换过去
- 当l<=r时结束
- r+1就是最终结果数组的长度
class Solution {
public int removeElement(int[] nums, int val) {
int l=0;
int r=nums.length-1;
while(l<=r){
if(nums[l]==val){
while(r>=l){// 这个while的判断语句试了好久才得出
// 边界测试如 [3] 2;[4,5] 5等想了很久
// while(r>0) {
// while(r>l){
if(nums[r]!=val){
nums[l]=nums[r];
r--;
break;
}
r--;
}
}
++l;
}
// r==-1的判断是为了[3] 3,这种情况
return r==-1?0:r+1;
}
}