Sort Colors

https://oj.leetcode.com/problems/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?

解题思路:
这道题上来就应该想到的是计数排序。因为只有0、1、2三种数字,第一遍遍历用三个count记录三个数字的数量,第二遍遍历给A这个数组赋上对应数量的0、1、2的值。时间复杂度为O(2n),是一个two-pass的方法,需要遍历两遍。于是有了以下代码。
public class Solution {

    public void sortColors(int[] A) {

        int redNum = 0;

        int whiteNum = 0;

        int blueNum = 0;

        

        for(int i = 0; i < A.length; i++){

            if(A[i] == 0){

                redNum++;

            }else if(A[i] == 1){

                whiteNum++;

            }else if(A[i] == 2){

                blueNum++;

            }

        }

        for(int i = 0; i < A.length; i++){

            if(i < redNum){

                A[i] = 0;

            }else if(i >= redNum && i < redNum + whiteNum){

                A[i] = 1;

            }else if(i >= redNum + whiteNum && i < redNum + whiteNum + blueNum){

                A[i] = 2;

            }

        }

    }

}

但是题目提出一个one-pass的解,要求仅遍历一遍。如何求解?

考虑两个pointer,分别为index0和index2,指向开头和结尾,标记如果遇到0和2,应该放置的位置。于是还需要一个i,从头至尾遍历整个数组。下面我们考虑i遇到0、1、2的三种情况。

如果在i处遇到0,代表它应该被放置到index0处。如果这是index0就是i,说明才开始,前面全是0,就不要动了,同时index0++,i++。如果这是index0<i,说明i这个地方的数字要被抛到前面去,于是swap(i, index0),这里为了简便,用坐标表示实际的数字。同时index0也必须++,落到下一个0需要移动到的位置。这里i不需要动,下次再看是什么。但是可以肯定的是1,为什么?因为如果i之前有2,一定早已被抛到最后去了。

如果i遇到2,那么swap(i, index2),即将其甩到结尾,同时index2--。这里i不能动,因为被抛到前面的,原来index2位置的数字,还不知道是什么,如果是2,就还要往后甩,如果是1还需要往前抛。

遇到1不做动作,i移到下一个目标。

循环终止的条件是i已经超过了index2,因为后面剩下的肯定都是2了。这里注意i==index2的时候还要判断,因为index2是下一个2准备放置的地方,还没有已经是2,也就是说,还未检测。

public class Solution {

    public void sortColors(int[] A) {

        int index0 = 0;

        int i = 0;

        int index2 = A.length - 1;

        

        while(i <= index2){

            if(A[i] == 0){

                if(i > index0){

                    int temp = A[i];

                    A[i] = A[index0];

                    A[index0] = temp;

                    index0++;

                }else{

                    i++;

                    index0++;

                }

                continue;

            }

            if(A[i] == 2){

                int temp = A[i];

                A[i] = A[index2];

                A[index2] = temp;

                index2--;

                continue;

            }

            if(A[i] == 1){

                i++;

            }

        }

    }

}

 

这个解法也是我参考了他人的解答才得出来的,不是很复杂,但是需要一定的逻辑和基础,也是想了半天才明白。这种two pointers的题目还有很多,值得细细体会。

http://fisherlei.blogspot.jp/2013/01/leetcode-sort-colors.html

http://blog.unieagle.net/2012/10/23/leetcode%E9%A2%98%E7%9B%AE%EF%BC%9Asort-colors/

http://blog.csdn.net/linhuanmars/article/details/24286349

update 2015/05/25:

写了个简单点的版本,容易理解了些

public class Solution {

    public void sortColors(int[] nums) {

        if(nums.length == 0) {

            return;

        }

        int zero = 0, two = nums.length - 1;

        for(int i = 0; i <= nums.length - 1; ) {

            if(nums[i] == 0 && i > zero) {

                int temp = nums[zero];

                nums[zero] = nums[i];

                nums[i] = temp;

                zero++;

                continue;

            }

            if(nums[i] == 2 && i < two) {

                int temp = nums[two];

                nums[two] = nums[i];

                nums[i] = temp;

                two--;

                continue;

            }

            i++;

        }

    }

}

 

你可能感兴趣的:(color)