【力扣150】移除元素图解 看完包懂的

58 阅读2分钟

Problem: 27. 移除元素

[TOC]

思路

为什么要使用左右指针?

如何才能移除等于val的值呢?把数组看成左右两个部分,其中左边都是不等于val的元素,右边都是等于val的元素,其中左边不等于val的元素数量就是k,k=nums.length - 右边等于val元素的数量。所以我们可以考虑使用左右指针

关于指针的移动

右指针负责寻找不等于val的元素的位置,左指针负责找等于val的元素的位置,然后两个元素交换,等于val的元素就移动到了右边,不等于val值得元素移动到了左边。

    //右指针的移动可以使用while循环来实现 (需要注意下标是否越界)
    while ( r >= 0 && nums[r] == val) {
        r--;
    }
    //指针也是同理 
    while (l < nums.length && nums[l] != val && l < r ) {
        l++;
    }

关于k的大小

从上述解释中,我们可以知道,右指针的移动条件(while循环成立的条件)是只有当指针指向的元素等于val的时候,右指针才会向左移动,所以就代表着右指针的移动步数就代表着等于val的元素个数,我们可以使用一个临时变量temp来计数,所以不等于val的元素个数就是nums.length - temp。值得注意的是,当交换之后,有右指针指向的仍然是等于val,所以当进入下一轮循环的时候这个交换后元素仍然会参与的计数,所以不会漏算。

图解

nums = [3,2,2,3]的时候

<image.png,image.png, image.png, image.png>

复杂度

  • 时间复杂度: O(N)O(N)
  • 空间复杂度: O(1)O(1)

Code

class Solution {
    public int removeElement(int[] nums, int val) {
        if (nums.length == 1) {
            return nums[0] == val ? 0 : 1;
        }
        int l = 0;
        int r = nums.length - 1;
        int ans = 0;
        while (l < r) {
            while (r >= 0 && nums[r] == val) {
                r--;
                ans++;
            }
            while (l < nums.length && nums[l] != val && l < r) {
                l++;
            }
            if (r >= 0 && l < nums.length) {
                int tmp = nums[l];
                nums[l] = nums[r];
                nums[r] = tmp;
            }

        }
        return nums.length - ans;
    }
}