LeetCode No.75

颜色分类

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地**对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

示例:

输入:** [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]</pre>

进阶:

  • 一个直观的解决方案是使用计数排序的两趟扫描算法。
    首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。
  • 你能想出一个仅使用常数空间的一趟扫描算法吗?

题目分析

  1. 相同元素相邻,换句话说即分区存放,一个颜色一个区域,但因为这里颜色使用0 ,1,2表示,即对一个012的无序序列进行排序,变成000...111....2222的顺序。

正常排序算法都适用,只不过这里注意仅有三种可能的顺序值,可以有特殊做法。

  1. 对于一个元素,我们将他分区时,肯定是插在区域的末尾,换句话说,我们只要保留每个区域的末尾下标,插入的时候交换过去就可以了。

三个区域,其实我们只要确定了两个区域即可确定第三个区域,因为0区域在最左边,2区域在最右边,方便程序定位,因此取0 2 的末尾指针保留下来。

  1. 确定了双指针确定区域,那么怎么进行遍历处理呢?确定了分类移动的位置,即cur遍历每一位的数值,分类处理遇到0放左边,遇到2放右边,02放好了,则1的区域也放好了。
针对cur的分类处理:
  1. 是0,则和0的flag ,left交换值,同时left++。此时cur获取的是之前的left交换过来的值。我们知道我们换过去的处理好了,那么这个换过来的还需要处理吗?目前还不知道,先看2的情况的处理。

  2. 是2,则和2的flag,right交换,同时right--。同样,此时cur获取了交换过来的值,由于这个值必然是在cur右边(因为它是原right,即cur的右边界),则cur肯定没有遍历过这个值。
    同时因为它在cur右边,它也不可能是交换过去的,因为交换过去的值肯定都在0 2 区域里了。
    因此这个值是野生的,所以cur在此停留,继续处理这个交换过来的值。

  3. 是1,因为我们把0 2 排序好,1的区域自然就出来了,因此1直接不处理,过就好了

  4. 那么看看0的情况交换过来的值?首先这个值的位置关系,即原left是在cur左边还是右边呢?

    只有当left会在cur右边时,left指向的才可能是cur没处理过的,但此时cur在left内部?那cur就是把一个0换到了外边,把一个乱序的换进了0的内部,内鬼毫无意义。

    当left在cur左边时,即left指向的必定经过了cur的洗礼,而且它必不是原来在后面被换到前面的,因为交换的肯定在left内部去了。所以它原值就是在那,且经过处理不用动,因此从left换到现在的cur之后,也是同样的处理,也不用动它,cur++拜拜嘞。

  5. 当cur遇到right,即到达2的边界,则说明不需要处理了,结束。

题解代码

class Solution {
public:
    void sortColors(vector<int>& nums) 
    {
        int left=0;
        int right=nums.size()-1;
        int cur=0;
        while(cur<=right)
        {   
            if(nums[cur]==0)//这个数字是0,移动0区域内,
            {
                swap(nums[cur],nums[left]);
                //假如cur>left,left交换过来的值肯定已经被处理过了,但是处理时产生交换,原left指向的,一定是不用处理的吗?
                //jeromememory:准确的说 cur 如果 与 p0 不是指向同一个索引,那 cur 指向的索引值如果发生交换,那交换过来的一定是 1(原因是只有当遍历过的节点有1,p0 和 cur 才不会同步),而 如果索引是 1 刚好也就不用有任何操作,所以可以直接++。
                //假如cur==left==0,没啥好说的,下一个
                //假如cur<left, 可能吗?cur++的机会 >= left++的机会
                left++;
            }
            else if(nums[cur]==2)//这个数字是2,移到2区域内
            {
                swap(nums[cur],nums[right]);
                right--;
                //交换过来的值,是右边过来的,cur没处理过,因此还需要对这个位置处理,--抵消++,位置不变
                cur--;
            }
            cur++;
        }
    }
};
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容