75.颜色分类
75.1 题目
给定一个包含红色、白色和蓝色的元素的数组 nums
,共有 n
个元素,使用整数 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
进阶:
你能想出一个仅使用常数空间的一趟扫描算法吗?
75.2 题解
计数排序
// 方法一:使用计数排序的思想,两趟扫描
static void SortColors1(int[] nums)
{
// 统计每种颜色的个数
int count0 = 0, count1 = 0, count2 = 0;
foreach (var num in nums)
{
if (num == 0)
count0++;
else if (num == 1)
count1++;
else if (num == 2)
count2++;
}
// 根据统计值重写数组
int i = 0;
while (count0 > 0)
{
nums[i++] = 0;
count0--;
}
while (count1 > 0)
{
nums[i++] = 1;
count1--;
}
while (count2 > 0)
{
nums[i++] = 2;
count2--;
}
}
使用指针多趟扫描
// 方法二:使用指针多趟扫描
static void SortColors2(int[] nums)
{
int left = 0; // 左指针,指向已经排好的0的右边界
int right = nums.Length - 1; // 右指针,指向已经排好的2的左边界
int curr = 0; // 当前考虑的元素
while (curr <= right)
{
if (nums[curr] == 0)
{
// 如果当前元素为0,交换到左边界
Swap(nums, curr, left);
left++;
curr++;
}
else if (nums[curr] == 2)
{
// 如果当前元素为2,交换到右边界
Swap(nums, curr, right);
right--;
}
else
{
// 如果当前元素为1,直接跳过
curr++;
}
}
}
// 辅助函数:交换数组中的两个元素
static void Swap(int[] nums, int i, int j)
{
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
75.3 代码
using System;
class Program
{
static void Main()
{
#region 题目
// 给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,
// 原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
// 使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
// 示例 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
// 进阶:
// 你能想出一个仅使用常数空间的一趟扫描算法吗?
#endregion
#region 测试
// 示例 1 方法1
int[] nums1 = { 2, 0, 2, 1, 1, 0 };
SortColors1(nums1);
Console.WriteLine($"示例1 方法1 输出:[{string.Join(",", nums1)}]");
// 示例 1 方法2
int[] nums2 = { 2, 0, 2, 1, 1, 0 };
SortColors2(nums2);
Console.WriteLine($"示例1 方法2 输出:[{string.Join(",", nums2)}]");
// 示例 2 方法1
int[] nums3 = { 2, 0, 1 };
SortColors1(nums3);
Console.WriteLine($"示例2 方法1 输出:[{string.Join(",", nums3)}]");
// 示例 2 方法2
int[] nums4 = { 2, 0, 1 };
SortColors2(nums4);
Console.WriteLine($"示例2 方法2 输出:[{string.Join(",", nums4)}]");
#endregion
}
#region 答案
// 方法一:使用计数排序的思想,两趟扫描
static void SortColors1(int[] nums)
{
// 统计每种颜色的个数
int count0 = 0, count1 = 0, count2 = 0;
foreach (var num in nums)
{
if (num == 0)
count0++;
else if (num == 1)
count1++;
else if (num == 2)
count2++;
}
// 根据统计值重写数组
int i = 0;
while (count0 > 0)
{
nums[i++] = 0;
count0--;
}
while (count1 > 0)
{
nums[i++] = 1;
count1--;
}
while (count2 > 0)
{
nums[i++] = 2;
count2--;
}
}
// 方法二:使用指针多趟扫描
static void SortColors2(int[] nums)
{
int left = 0; // 左指针,指向已经排好的0的右边界
int right = nums.Length - 1; // 右指针,指向已经排好的2的左边界
int curr = 0; // 当前考虑的元素
while (curr <= right)
{
if (nums[curr] == 0)
{
// 如果当前元素为0,交换到左边界
Swap(nums, curr, left);
left++;
curr++;
}
else if (nums[curr] == 2)
{
// 如果当前元素为2,交换到右边界
Swap(nums, curr, right);
right--;
}
else
{
// 如果当前元素为1,直接跳过
curr++;
}
}
}
// 辅助函数:交换数组中的两个元素
static void Swap(int[] nums, int i, int j)
{
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
#endregion
}
75.4 运行结果
示例1 方法1 输出:[0,0,1,1,2,2]
示例1 方法2 输出:[0,0,1,1,2,2]
示例2 方法1 输出:[0,1,2]
示例2 方法2 输出:[0,1,2]
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com