给定一个数组 nums 和一个值 val,你须要原地移除全部数值等于 val 的元素,返回移除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。数组
元素的顺序能够改变。你不须要考虑数组中超出新长度后面的元素。性能
1.先来写一个最简单的版本,即便用额外空间做为辅助,把符合条件的元素写到一个新的数组里。优化
public static ArrayList removeElement(int[] nums, int val) { ArrayList<Integer> newNums = new ArrayList<Integer>(); for (int item:nums) { if(item != val) { newNums.add(item); } } System.out.print(newNums.size()); return newNums; }
基础知识查漏补缺:
1.Java数组的声明、初始化和使用
遇到了一个问题,新的数组须要声明和初始化,可是新数组的长度还不知道,怎么初始化。
考虑使用ArrayList
2.ArrayList的声明和使用
3.静态方法中调用非静态方法的限制指针
上述方法:
1.须要遍历数组一次,因此时间复杂度是o(n)
2.须要使用一个数组做为额外空间,因此空间复杂度是o(n)code
2.还有没有优化空间?
进阶版本--下降空间复杂度
思路:
方法1须要开辟一个新的数组空间,然而题目中给定的说明,不须要考虑数组中超出长度后面的元素,能够考虑把旧数组的空间再利用。
因为必需要根据索引替换数组的值,因此不能用For-Each循环方法。索引
public static int removeElement(int[] nums, int val) { int j = 0; for (int i = 0;i < nums.length;i++) { if(nums[i] != val) { nums[j] = nums[i]; j++; } } System.out.print(j); return j; }
复杂度分析:
时间复杂度:o(n) 遍历2n次
空间复杂度:o(1)rem
3.还有没有优化空间?
方法2在某些特定场景下会进行没必要要的复制操做,影响性能。好比{1,2,3,5,4} val=4,或者{4,1,2,3,5},彷佛没有必要把前4个元素复制一遍,在这一点上能够进行优化,优化思路为若是匹配到须要剔除的元素,就把数组末尾的元素替换到这个位置来。注意:尾部的元素有多是须要剔除的,因此,下一轮循环要从当前索引从新开始。it
public static int removeElement(int[] nums, int val) { int n = nums.length; System.out.print(n); for (int i = 0;i < n;i++) { if(nums[i] == val) { nums[i] = nums[n-1]; i--; n--; System.out.println("1:n--:"+n); } } System.out.print(n); return n; }
遇到的问题:
1.在循环里,把nums.length做为了固定长度,会致使全部元素都被遍历,实际上被替换到前面的元素不须要被遍历,致使了bug
2.在使用i--时,考虑若是数组前几个元素都是须要被剔除的元素,会不会致使index为负,致使溢出。通过分析和实验不会,由于每次循环结束i都要++基础
复杂度分析:
时间复杂度:o(n) 遍历n次
空间复杂度:o(1) List
总结:1.学会的新方法,双指针法2.若是没有广泛的优化方法,那么就考虑业务场景的特色,好比方法三,针对某些特殊场景提出优化空间。