LC 75. Sort Colors 双指针 对只含0、1、2的数组的排序,一次遍历

本文探讨了一种针对只包含0,1,2的整数数组排序的问题,提出了使用计数器进行两遍扫描的直观解决方案,并进一步介绍了一种仅需一次遍历的高效算法。通过维护两端指针来实现原地排序,避免了额外的空间开销。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue.

Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.

Note:
You are not suppose to use the library's sort function for this problem.

Follow up:
A rather straight forward solution is a two-pass algorithm using counting sort.
First, iterate the array counting number of 0's, 1's, and 2's, then overwrite array with total number of 0's, then 1's and followed by 2's.

Could you come up with an one-pass algorithm using only constant space?

问题其实就是给只包含0,1,2的整数数组排序。

看到题目马上就能想到一种直观的解决方法。思路一:用三个计数器分别记下0,1,2出现的次数,然后用循环把对应个数的数字放进原数组。Follow up说了这种straightforward的solution需要两趟遍历,有没有更简单的解决办法?

一趟遍历解决,我首先想到了前两天复习过的快排算法的partition函数。快排种一般取nums[0]为pivot,然后partition完成将大于pivot的数字放左边,大于pivot的数放右边。这个问题中,想找到pivot=1并不是一件容易的事,因为必须保证找到的pivot左边全部都是0(否则再次调整就又涉及到第二次遍历了)。

我用快排的思路想了一个小时还没有解决这个问题,最后看了下别人的解答。看代码:


void sortColors(vector<int>& nums) {
    int zero = 0, two = (int)nums.size() - 1;
    for (int i = 0; i <= two; i++) {
        while (nums[i] == 2 && i < two) {
            swap(nums[i], nums[two]);
            two--;
        }
        while (nums[i] == 0 && i > zero) {
            // i > zero condition ensures that when nums[] = {0}, it doesn't swap(nums[0], nums[0]) forever.
            swap(nums[i], nums[zero]);
            zero++;
        }
    }
}

zero和two分别维护从两侧向中间生长的全0和全2子串,它们指向的地方是下一个0或2要被插入的地方,新插入的数字来自于nums[zero...two]这个逐渐缩短的区间。需要注意的是第二个while循环中要设置条件 i > zero,用来跳过第一次运行时的corner case。两个判断是while而不是if的原因是可能nums[i]在经历第一次swap之后换来的还是原来的那个数字,即有可能:

nums[i] = nums[two] = 0 或 2

今天清明节,凌晨错过了巴萨罗马的欧冠比赛,上午睡到十点多起床。昨晚开始看CMU的Intro. to Computer Systems 15-213的公开课视频了,后续还有CS61B和OS要看,争取在去SD之前看完。昨天刷了4道还是5道题,终于LC刷题数过100了。今天白天刷了两道easy题和这个medium,虽然medium这个做的不理想。加油吧,要时刻认识到自己还是个菜鸡。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值