力扣链接:力扣
要点:
1. 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。不需要考虑数组中超出新长度后面的元素。
2. 本质上就是移动目标元素到数组的最后,实现不难,但是相比于暴力解法的两层for循环O(n^2),可以使用更巧妙的双指针法,时间复杂度为O(n)。
最初思路是找到目标元素与数组最后一个元素交换,但是没法解决数组元素全部都是目标元素的情况,例如输入 [3,3], 3 while就会陷入死循环。
最初代码如下:
public void temp(int[] nums, int i, int j){
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
public int removeElement(int[] nums, int val){
if (nums.length==1){
if(nums[0] == val)
return 0;
else
return 1;
}else if(nums.length == 0){
return 0;
}
int j = nums.length-1;
for(int i = 0; i<nums.length; i++){
if(nums[i]==val){
while(nums[j]==val){
j--;
}
temp(nums, i, j);
j--;
}else {
if(i==j){
break;
}
}
}
return j+1;
}
更换思路,使用双层for循环按元素逐个交换:
代码:
public int removeElement(int[] nums, int val){
int l = nums.length;
for (int i = 0; i < l; i++) {
if(nums[i] == val){
for (int j = i; j < l-1; j++) {
temp(nums, j, j+1);
}
i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
l--;
}
}
return l;
}
利用双指针法,j指针遍历数组,遇到相同元素就用j指针指向的元素与i指针指向的元素交换,返回i
改进代码:
public int removeElement(int[] nums, int val){
int l = nums.length;
int i = 0;
for (int j = 0; j < l; j++) {
if(nums[j]!=val){
temp(nums, i, j);
i++;
}
}
return i;
}