题目描述
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意:
不能使用代码库中的排序函数来解决这道题。
样例
输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]
进阶:
- 一个直观的解决方案是使用计数排序的两趟扫描算法。
首先,迭代计算出0
、1
和2
元素的个数,然后按照0
、1
、2
的排序,重写当前数组。 - 你能想出一个仅使用常数空间的一趟扫描算法吗?
算法分析
一道很难想的题目,具体情况请参考y总的视频
如图所示,[0,i - 1]
维护的是全是0
的区间,[i,j - 1]
维护的是全是1
的区间,[k + 1,n - 1]
维护的是全是2
的区间,而[i,k]
区间的元素是还没放的数
枚举整个数组,若当前枚举到的位置是i
,
- 1、若
nums[i] == 0
,则交换i
和j
的位置的元素,由于nums[i] == 0
且nums[j] == 1
,因此交换后i
和j
同时往后移动1
位 - 2、若
nums[i] == 1
,则直接i ++
- 3、若
nums[i] == 2
,则交换i
和k
位置的元素,由于nums[i] == 2
,因此填入到k
位置时,k
的元素就是2
,因此k
需要往前移动1
位,而i
的元素未知,不做移动
时间复杂度 $O(n)$
Java 代码
class Solution {
static void swap(int[] nums,int a,int b)
{
int t = nums[a];
nums[a] = nums[b];
nums[b] = t;
}
public void sortColors(int[] nums) {
for(int j = 0,i = 0,k = nums.length - 1;i <= k;)
{
if(nums[i] == 0) swap(nums,i ++ ,j ++);
else if(nums[i] == 2) swap(nums,i,k --);
else i ++;
}
}
}
[0, j - 1] 维护一个全是0的区间,[j, i - 1] 维护全是1的区间, 是不是应该这样的。
对