给你一个数组 nums?和一个值 val,你需要 原地 移除所有数值等于?val?的元素,并返回移除后数组的新长度。 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
基本思路是遍历数组,遇到和val相等的,就使用‘最后一个’赋值。最后就会去掉所有的val等值元素。
public int removeElement(int[] nums, int val) {
int len = nums.length;
int delCount=0;
for(int i=0;i<len-delCount;i++){
if(val==nums[i]){
nums[i]=nums[len-delCount-1];//把和val等值的覆盖掉
delCount++;//删除值的数量+1
if(nums[i]==val) i--; //如果新值还是和val相等,i--抵消掉for的i++,原地再次替换掉。
}
}
return len-delCount;
}
本来以为这题很简单,上面的就已经击败100%的用户了
没想到
还有更好的写法:
public int removeElement(int[] nums, int val) {
int k =0;
for(int i=0;i<nums.length;i++){
if(val!=nums[i]){
nums[k++]=nums[i];
}
}
return k;
}
这个算法更巧妙
和前面从后取值覆盖前值的思维不同,这里是值前移的思维(k<=i始终成立,从而可以前移)
代码更加简洁
但是仔细思考下,这里每一个合法的值都会做一次移动,对于只有个别值和val相同的情况,做了太多次的无效移动,实则不好。
对于大多数值都需要去除的情况,则减少了数组赋值的次数。
于是:
这两种解法实则是等价的,在不同的情况下有不同的效率。
原文:https://www.cnblogs.com/XT-xutao/p/12501293.html