LeetCode 75.颜色分类

129 阅读2分钟

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

题目:给定一个包含三种颜色的数组,三种颜色分别用0、1、2表示,要求对这个数组原地排序,使得颜色相同的元素相邻,并且按照颜色顺序012排序。不能使用库已有的sort函数。

解题思路

本题是一个经典的荷兰国旗问题,实际上荷兰国旗就是快速排序的一趟实现,本题可以直接使用一趟的快速排序解决,此时选择的基准值需为1。当然使用任意一种排序方法都可以解决本题,所不同的只是时间复杂度和空间复杂度的不同。另一种思路是在原数组设置大于区域的边界和小于区域的边界,此时数组遍历完了数组排序也完成,边界设置如下:

1640311130827.png

初始时数组的索引左侧为左边界,数组的索引右边为右边界,当遍历数组元素发现数组元素小于所选的基准值时,数组左边元素和当前元素互换,原索引自增。如果遍历的元素大于所选的基准值,则数组右边元素和当前元素互换,原索引不变,继续比较该索引元素,直至最后原数组即为排序完成的数组,代码如下:

public void sortColors(int[] nums) {
		int L=-1;
        int R=nums.length;
        int cur=0;
        while(cur<R){
            if(nums[cur]>1){
                swap(nums, --R, cur);
            }else if(nums[cur]<1){
                swap(nums, ++L, cur++);
            }else {
                cur++;
            }
        }
    }

    public void swap(int[] nums, int a, int b){
        int temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }

上述代码时间复杂度为O(N)O(N),空间复杂度为O(1)O(1)

快速排序

通过本题可以复习一下快速排序的内容,快速排序每次选定一个基准值,使得数组左边的内容小于此基准值,数组右边的内容大于此基准值,之后递归对左右两边的数组内容继续排序,直到每个数组的元素为1个为止,快速排序的代码如下:

public static void quicksort(int[] arr, int L, int R){
        int i = L;
        int j = R;

        //支点
        int pivot = arr[(L + R) / 2];

        //左右两端进行扫描,只要两端还没有交替,就一直扫描
        while (i <= j) {

            //寻找直到比支点大的数
            while (pivot > arr[i])
                i++;

            //寻找直到比支点小的数
            while (pivot < arr[j])
                j--;

            //此时已经分别找到了比支点小的数(右边)、比支点大的数(左边),它们进行交换
            if (i <= j) {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
                i++;
                j--;
            }
        }
        //上面一个while保证了第一趟排序支点的左边比支点小,支点的右边比支点大了。


        //“左边”再做排序,直到左边剩下一个数(递归出口)
        if (L < j)
            quicksort(arr, L, j);

        //“右边”再做排序,直到右边剩下一个数(递归出口)
        if (i < R)
            quicksort(arr, i, R);
    }

上述代码参考来源:快速排序就这么简单 - 知乎 (zhihu.com)