LeetCode----Sort Colors

95 篇文章 0 订阅
93 篇文章 0 订阅

Sort Colors

 

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.

click to show follow up.

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?


分析1:

对一个取值只有0,1,2三种元素的数组进行排序。如果你看Follow up你会发现你可以使用计数排序。当然这题的解法非常之多,你可以找下其他的解法。

我的思路是:首先对数组进行0和1的交换排序,即数组[2, 1, 0, 0, 1, 2, 1, 2, 1]会变成[0, 0, 1, 2, 1, 2, 1, 2, 1],其中0和1的相对顺序已经确定了,再对数组进行1和2的交换排序,数组会从[0, 0, 1, 2, 1, 2, 1, 2, 1]变成[0, 0, 1, 1, 1, 1, 2, 2, 2],这样1和2的相对顺序也确定了,从而确定了整个的数组顺序。


代码1:

class Solution(object):
    def sortColors(self, nums):
        """
        :type nums: List[int]
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        nums_len = len(nums)
        left = 0
        right = nums_len - 1
        # Swap 0 and 1
        while left <= right:
            if nums[left] == 1 or nums[left] == 2:
                if nums[right] == 0:
                    nums[left], nums[right] = nums[right], nums[left]
                else:
                    right -= 1
            else:
                left += 1
        # Swap 1 and 2
        right = nums_len - 1
        while left <= right:
            if nums[left] == 2:
                if nums[right] == 1:
                    nums[left], nums[right] = nums[right], nums[left]
                else:
                    right -= 1
            else:
                left += 1


分析2:

在看了Follow up后,发现题目的要求是one-pass和常量空间的算法,而上面的算法需要对数组进行2遍的扫描,所以是不符合要求的。后来的思路是,left为左边的坐标,初始为0,right为右边的坐标,初始为len(nums) - 1,一遍扫描数组,遇到0则将该数放置到左边的位置,遇到1则跳过,遇到2则将该数放到右边的位置。这种方法很巧妙,但是在实现的时候有一些细节要注意。


代码2:

class Solution(object):
    def sortColors(self, nums):
        """
        :type nums: List[int]
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        nums_len = len(nums)
        left = 0
        right = nums_len - 1
        i = 0
        while i <= right:
            if nums[i] == 0:
                nums[i], nums[left] = nums[left], nums[i]
                i += 1
                left += 1
            elif nums[i] == 2:
                nums[i], nums[right] = nums[right], nums[i]
                right -= 1
            else:
                i += 1

简单证明代码2:

代码2的思路是,每遇到一个元素,则将其该元素放置到它恰当的位置,比如遇到0放到左边,遇到2放到右边。

初始的时候,我们以left表示遍历时遇到0时进行交换的下标,以right表示遍历时遇到2时进行交换的下标,以i表示遍历的当前下标,为了理解可以认为left左边的元素均为0,right右边的元素均为2。

当算法进行遍历时,我们是将nums[i]的元素放到对应的位置上时才接着遍历第二个元素。比如,i == 0 时,(1)遇到的第一个数是0,我们也将left和i下标的元素进行交换,之后left++和i++,此时做的虽然看似是无用功,但是能够保证左边left之前的元素均为0;(2)如果遇到的数是2,我们将该元素与right下标的元素进行交换,right--,此时,能够保证right右边的元素为2,注意此时不要进行i++,因为right对应的元素还需要进一步处理,比如right对应的元素是2,我们还需要将它再放到右边的位置;(3)如果遇到的数是1,那么不进行交换,i++,处理下一个数。注意,在(2)中,当遇到元素是2时,交换后我们没有进行i++,所以,循环还会对交换后的元素再进行(1),(2)和(3)的处理,这样能够保证i遍历过的每一个0和2都被放置了合适的位置上。

当i > right时,我们已经确定left左边所有元素均为0,right右边的所有元素均为2,而从 left->i,所有的0已经放入了left的左边,所有1已经放入了right的右边,也就说,left到i之间的元素均为1。此时已经可以看到,所有0在左边,所有的1在中间,所有的2在右边,即数组排序成功循环结束。

最后,我们来看下这循环的次数是否满足要求。设数组长度为nums_len,0出现的次数为num_0,1出现的次数为num_1,2出现的次数为num_2,在循环中每次会选择if-else分支的某一个去执行,三个分支执行次数的总和即为循环的总次数。在执行if nums[i] == 0和else时,i++了,所以这两个分支最后共执行了nums_len - num_2次(因为循环结束的条件是i <= right),注意right右边全为2,即(num_len - (right + 1)) == (nums_len - num_2)。再看中间的判断分支,遍历时,数组中的全部的2均会被遍历到,所以共执行num_2次,所以一共执行(nums_len - num_2 + num_2 )== (nums_len)次,即在O(nums_len)的时间内完成,满足题目要求。









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值