题目描述:
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
解题思路:
首先我们应该明确题目的意思:**元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。**即我们可以将要输出的数组直接在原来数组的基础上进行修改即我们最总要将数组中不等于val的数值移动到一侧再统计其长度,将等于val的值移动到数组另一侧那么我们可以使用双指针算法,具体操作如下:
1.定义左右指针分别指向数组的两头,如果左指针小于右指针同时此时左指针指向的元素不等于val则将左指针向左移动一位;如果左指针小于右指针同时右指针指向的元素等于val,则将右指针向右移动一位。
2.交换此时左右指针指向的值
3.若最后左指针指向的值等于val则直接返回左指针,否则返回左指针加一!!!
对于第三点可能会有些疑问,我们看一个“栗子”!
假设**在已经进行如上的操作后的数组为:
[2, 2, 3, 3]a:若以上数组最后操作后的左指针指向的为2(即此时nums[left] != val 为1)但是我们此时要饭返回的是数组的长度,则此时我们要返回left + 1
b:若以上数组最后操作后的左指针指向的为3(即此时nums[left] == val 为2)则我们直接返回left
代码:
class Solution {
public int removeElement(int[] nums, int val) {
//Tow pointers
//N is the size of nums
//Time Complexity: O(N)
//Space Complexity: O(1)
if (nums == null || nums.length == 0) {
return 0;
}
//左右指针
int left = 0;
int right = nums.length - 1;
while (left < right) {
if (left < right && nums[left] != val) {
left++;
}
if (left < right && nums[right] == val) {
right--;
}
//交换
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
//如果最后左指针指向等于val则直接返回,否则返回left + 1
return nums[left] == val ? left : left+1;
}
}
补充:
可能有的“童鞋”和我一开始都也会遗漏到一点:
while (left < right) {
if (left < right && nums[left] != val) {
left++;
}
if (left < right && nums[right] == val) {
right--;
}
也就是我想说有人能会问循环判断已经有了条件left < right*了为什么在移动指针时还要进行判断?*我们看一个错误例子就会明白其作用!!!
若出现这种情况我们不加以以上条件(在移动指针时)最后对于调用者返回的内容就不符合题意所需!