【LeetCode】75. 颜色分类

109 阅读2分钟

「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战」。

题目

给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

我们使用整数 0、1 和 2 分别表示红色、白色和蓝色。

必须在不使用库的sort函数的情况下解决这个问题。

示例 1

输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

示例 2

输入:nums = [2,0,1]
输出:[0,1,2]

提示

  • n == nums.length
  • 1 <= n <= 300
  • nums[i] 为 0、1 或 2

题解

思路

left为数字0的右开边界,right为数字2的左开边界。

00001102001112222
    l       r
  • 当把 i 交换到左边界的时候:i 可以直接 +1 推进,因为左边不会有数字 2 了。
  • 当把 i 交换到右边界的时候:可能会把数字 2 或者数字 0 置换 i 位置上,所以我们不能推进 i。

如果你还是对 i 的变化感到迷惑,那么下面是更加详细的解释:

i 位置上的数字代表着我们当前需要处理的数字。当 i 为数字 1 的时候,我们什么都不需要做,直接 +1 即可。如果是 0,我们放到左边,如果是 2,放到右边。

right 指针上的数字交换到 i 位置上以后,我们还需要对该数字进行处理。这个数字是一个全新的(0, 1, 2 都有可能),没有处理过的数字。

如果交换过来数字 0 或者数字 2 了,我们推进了 i 的话,那么就会出错。

而需要交换 i 位置数字到 left 上时,那么 i 位置上的数字一定是 0。我们可以分成两种情况来讨论:

  1. left 和 i 和重合:那么就相当于 i 和 i 自己交换,此时 i 位置上的数字就处理完了,i 和 left 都可以推进。
  2. i 和 left 不重合:那么 left 对应的数字一定是 1,如果不是 1 的话,left 和 i 一定是重合的(包含一种特殊情况,数组中只有 0 和 2 的时候)。此时交换完以后,i 位置上就会是 1,那么也可以直接 +1 推进。

代码

class Solution {
    public void sortColors(int[] nums) {
        int left=0,right=nums.length-1;
        int i=0;
        while(i<=right){
            if(nums[i]==0)
                swap(nums,i++,left++);
            else if(nums[i]==2)
                swap(nums,i,right--);
            else
                i++;
        }
    }
    private void swap(int[] nums,int i,int j){
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }
}

结语

业精于勤,荒于嬉;行成于思,毁于随。