2. Remove elements - easy

2. Remove elements - easy

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

illustrate:

Why is the returned value an integer but the output answer is an array?

Please note that the input array is passed by "reference", which means that modifications to the input array in the function are visible to the caller.

You can imagine the internal operation as follows:

// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
    
    
    print(nums[i]);
}

Example 1

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

Example 2

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

Solution 1

Method 1: Double pointer
ideas and algorithms

Since the question requires deleting elements equal to val in the array, the length of the output array must be less than or equal to the length of the input array. We can write the output array directly on the input array. You can use double pointers: the right pointer points to the current element to be processed, and the left pointer left points to the next location to be assigned a value.

  • If the element pointed by the right pointer is not equal to val, it must be an element of the output array. We copy the element pointed by the right pointer to the left pointer position, and then move the left and right pointers to the right at the same time;

  • If the element pointed to by the right pointer is equal to val, it cannot be in the output array. At this time, the left pointer does not move and the right pointer moves one position to the right.

The property that remains unchanged throughout the process is: none of the elements in the interval [0,left)[0,left) is equal to val. After the left and right pointers have traversed the input array, the value of left is the length of the output array.

In the worst case of such an algorithm (no element in the input array is equal to val), the left and right pointers each traverse the array once.

Code:

class Solution {
    
    
    public int removeElement(int[] nums, int val) {
    
    
        int n = nums.length;
        int left = 0;
        for (int right = 0; right < n; right++) {
    
    
            if (nums[right] != val) {
    
    
                nums[left] = nums[right];
                left++;
            }
        }
        return left;
    }
}

Solution 2

Method 2: Double pointer optimization
idea

If the element to be removed happens to be at the beginning of the array, such as the sequence [1,2,3,4,5], when val is 1, we need to shift each element to the left by one bit. Notice that the title says: "The order of elements can be changed." In fact, we can directly move the last element 5 to the beginning of the sequence, replace element 1, and obtain the sequence [5, 2, 3, 4], which also meets the requirements of the question. This optimization works well when the number of val elements in the sequence is small.

In terms of implementation, we still use double pointers. The two pointers are initially located at the beginning and end of the array, and move toward the middle to traverse the sequence.

algorithm

If the element pointed by the left pointer left is equal to val, the element pointed by the right pointer right is copied to the position of the left pointer left, and then the right pointer right is shifted one position to the left. If the assigned element happens to be equal to val, you can continue to assign the value of the element pointed to by the right pointer (the position of the element equal to val pointed by the left pointer continues to be overwritten) until the value of the element pointed by the left pointer is not equal to until val.

When the left pointer left and the right pointer coincide, the left and right pointers have traversed all the elements in the array.

In this way, the two pointers combined only traverse the array once in the worst case. Different from method one, method two avoids repeated assignment operations of elements that need to be retained.

code

class Solution {
    
    
    public int removeElement(int[] nums, int val) {
    
    
        int left = 0;
        int right = nums.length;
        while (left < right) {
    
    
            if (nums[left] == val) {
    
    
                nums[left] = nums[right - 1];
                right--;
            } else {
    
    
                left++;
            }
        }
        return left;
    }
}

Guess you like

Origin blog.csdn.net/weixin_44796239/article/details/130590635