75. 颜色分类
题目描述
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意:
不能使用代码库中的排序函数来解决这道题。
示例:
输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]
进阶:
一个直观的解决方案是使用计数排序的两趟扫描算法。 首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。 你能想出一个仅使用常数空间的一趟扫描算法吗?
思路一:不借助计数排序,但是需要两次遍历
思路和交换0很像,也是使用一个下标指向下个0应该存放的位置,另一个指针碰到0后把这个0放到正确的位置即可,但是这里有3个数,分别是0, 1, 2, 所以应该遍历两遍,第一遍把所有0都放到最前面,第二遍把所有2放在最后面
1 class Solution { 2 public void sortColors(int[] nums) { 3 int len = nums.length; 4 int next = 0; 5 // 把所有的0移到最前面 6 for(int i = 0; i < len; i++){ 7 if(nums[i] == 0){ 8 int temp = nums[next]; 9 nums[next++] = nums[i]; 10 nums[i] = temp; 11 } 12 } 13 14 // 把所有的2移到最后面 15 next = len - 1; 16 for(int i = len - 1; i >= 0; i--){ 17 if(nums[i] == 2){ 18 int temp = nums[next]; 19 nums[next--] = nums[i]; 20 nums[i] = temp; 21 } 22 } 23 } 24 }
leetcode 执行用时:0 ms > 100.00%, 内存消耗:37.3 MB > 54.12%
复杂度分析:
时间复杂度:分别正序和倒序遍历了一次数组,所以时间复杂度为O(2n)
空间复杂度:O(1)
思路二:双指针 + 一次遍历
其实就是思路一的一个改进版
分别使用一个指针 p0 指向下个0的应该放置的位置,使用一个p2 指向下个 2 应该放置的位置。另一个指针 i 从前往后扫描,碰到 0 就和 p0所指的元素进行交换,然后p0 指针后移,碰到 2 就和 p2 所指元素进行交换,p2--, 但是这时 i 不能前移,因为不能确定nums[i]和 nums[p2]进行交换后,如果是0的话需要和nums[p0]交换,所以需要下轮继续判断nums[i]
1 class Solution { 2 public void sortColors(int[] nums) { 3 int len = nums.length; 4 5 int p0 = 0, p2 = len - 1; 6 for(int i = 0; i <= p2; i++){ 7 if(nums[i] == 2){ 8 // 因为不能确定nums[p2]是什么,如果是0的话需要和nums[p0]交换,所以需要下轮继续判断nums[i] 9 nums[i--] = nums[p2]; 10 nums[p2--] = 2; 11 }else if(nums[i] == 0){ 12 nums[i] = nums[p0]; 13 nums[p0++] = 0; 14 } 15 } 16 } 17 }
leetcode 执行用时:0 ms > 100.00%, 内存消耗:37.3 MB > 64.88%
复杂度分析:
时间复杂度:只遍历了一遍数组,所以时间复杂度为O(n)
空间复杂度:O(1)