75. 颜色分类
题目描述
给定一个包含红色、白色和蓝色,共 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
指向数组的开头,一个右指针right
指向数组的末尾。左指针用来寻找非红色(即1
或2
)的元素,右指针用来寻找非蓝色(即0
或1
)的元素。 - 然后从数组的开头开始遍历,当遇到
0
时,将其与左指针指向的元素交换,因为左指针左边的元素应该都是0
(红色),这样就保证了红色元素在数组的左边部分逐渐增多;当遇到2
时,将其与右指针指向的元素交换,因为右指针右边的元素应该都是2
(蓝色),这样就保证了蓝色元素在数组的右边部分逐渐增多。 - 对于遇到的
1
,不需要进行交换操作,因为1
(白色)本来就是在中间的位置,随着0
和2
的交换,1
会自然地处于正确的位置。
- 我们可以使用两个指针,一个左指针
(二)单指针法(一趟扫描算法,满足进阶要求)
- 思路:
- 定义一个指针
curr
,初始时指向数组的开头。再定义两个变量zero_end
和two_start
,分别用来记录0
的末尾位置和2
的起始位置(初始时都为0
)。 - 从数组的开头开始遍历,当遇到
0
时,将其与curr
指向的元素交换,并且更新zero_end
为curr
的位置,然后curr
向前移动一位;当遇到2
时,将其与curr
指向的元素交换,并且更新two_start
为curr
的位置,但是这里curr
不移动,因为交换过来的元素可能是0
或1
,需要再次判断。当遇到1
时,curr
直接向前移动一位。 - 通过这样一趟扫描,就可以将数组中的元素按照红色、白色、蓝色的顺序排列好,并且只使用了常数空间。
- 定义一个指针
八、代码实现
(一)双指针法
def sortColors(nums):
left = 0
right = len(nums) - 1
i = 0
while i <= right:
if nums[i] == 0:
nums[i], nums[left] = nums[left], nums[i]
left += 1
i += 1
elif nums[i] == 2:
nums[i], nums[right] = nums[right], nums[i]
right -= 1
else:
i += 1
return nums
(二)单指针法(一趟扫描算法)
def sortColors(nums):
curr = 0
zero_end = 0
two_start = len(nums)
while curr < two_start:
if nums[curr] == 0:
nums[curr], nums[zero_end] = nums[zero_end], nums[curr]
zero_end += 1
curr += 1
elif nums[curr] == 2:
nums[curr], nums[two_start - 1] = nums[two_start - 1], nums[curr]
two_start -= 1
else:
curr += 1
return nums
九、测试用例
(一)双指针法
测试用例1
输入:nums = [2, 0, 2, 1, 1, 0]
预期输出:[0, 0, 1, 1, 2, 2]
测试用例2
输入:nums = [2, 0, 1]
预期输出:[0, 1, 2]
测试用例3
输入:nums = [0, 1, 2, 2, 1, 0]
预期输出:[0, 0, 1, 1, 2, 2]
(二)单指针法(一趟扫描算法)
测试用例1
输入:nums = [2, 0, 2, 1, 1, 0]
预期输出:[0, 0, 1, 1, 2, 2]
测试用例2
输入:nums = [2, 0, 1]
预期输出:[0, 1, 2]
测试用例3
输入:nums = [0, 1, 2, 2, 1, 0]
预期输出:[0, 0, 1, 1, 2, 2]
十、测试结果
通过对上述测试用例的测试,两种方法的代码都能够正确地对给定数组进行排序,满足题目要求。双指针法和单指针法(一趟扫描算法)在不同的应用场景下都可以有效地解决颜色分类问题。