刷题系列之75. 颜色分类

139 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情

前言

题目来源

leetcode.cn/leetbook/re…

题目介绍

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

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

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

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

题目分析

根据题目和示意,我们知道就是按顺序排放元素,按从小到大排序。因此可以知道应该循环数组,遍历元素,比较当前元素和后面元素的大小,如果碰到比自己大的就交换位置。

题目解答

class Solution {
    public void sortColors(int[] nums) {
        int numsSize=nums.length;
        //遍历循环整个数组
      for (int i = 0; i < numsSize - 1; i++) {
          //每个数组元素和剩下的元素相比较
            for (int j = i + 1; j < numsSize; j++) {
                //如果当前元素比剩余元素大,那么交换2个的位置
                if (nums[j] < nums[i]) {
                    int temp = nums[i];
                    nums[i] = nums[j];
                    nums[j] = temp;
                }
            }
        }
    }
}

这里进行了2次for循环,值的注意的是,第一层遍历只需要遍历到倒数第二个元素就行,因此numsSize - 1,内部在来一个for循环,遍历后面的元素(i+1),一直到最后一个,然后比较大小,大的就往后移动交换位置。,结果如下

image.png

用了2个for循环,还是比较耗性能,不是那么完美。

官方答案分析

class Solution {
    public void sortColors(int[] nums) {
        int n = nums.length;
        int ptr = 0;
        for (int i = 0; i < n; ++i) {
            if (nums[i] == 0) {
                int temp = nums[i];
                nums[i] = nums[ptr];
                nums[ptr] = temp;
                ++ptr;
            }
        }
        for (int i = ptr; i < n; ++i) {
            if (nums[i] == 1) {
                int temp = nums[i];
                nums[i] = nums[ptr];
                nums[ptr] = temp;
                ++ptr;
            }
        }
    }
}

官方的思路是在第一次遍历中,从左向右遍历整个数组,如果找到了 0,那么就需要将 0 与「头部」位置的元素进行交换,并将「头部」向后扩充一个位置。在遍历结束之后,所有的 0 都被交换到「头部」的范围,并且「头部」只包含 0。

在第二次遍历中,我们从「头部」开始,从左向右遍历整个数组,如果找到了 1,那么就需要将 1 与「头部」位置的元素进行交换,并将「头部」向后扩充一个位置。在遍历结束之后,所有的 1 都被交换到「头部」的范围,并且都在 0 之后,此时 2 只出现在「头部」之外的位置,因此排序完成。

image.png 可以看出这种方式执行效率高了很多。

总结

可以看出这题还是数组类问题,要理解遍历循环、交换位置、排序等概念。