1. 程式人生 > >算法系列--荷蘭國旗問題

算法系列--荷蘭國旗問題

【問題】

現有紅白藍三個不同顏色的小球,亂序排列在一起,請重新排列這些小球,使得紅白藍三色的同顏色的球在一起。這個問題之所以叫荷蘭國旗問題,是因為我們可以將紅白藍三色小球想象成條狀物,有序排列後正好組成荷蘭國旗。

【分析】

這個問題我們可以將這個問題視為一個數組排序問題。紅白藍分別對應數字0、1、2。紅、白、藍三色小球數量並不一定相同。

【思路一】

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.

(1)遍歷陣列,統計紅白藍三色球(0,1,2)的個數

(2)根據紅白藍三色球(0,1,2)的個數重排陣列

時間複雜度:O(n)
【程式碼一】

    /**------------------------------------
    *   日期:2015-02-02
    *   作者:SJF0115
    *   題目: 75.Sort Colors
    *   網址:https://oj.leetcode.com/problems/sort-colors/
    *   結果:AC
    *   來源:LeetCode
    *   部落格:
    ---------------------------------------**/
class Solution { public: void sortColors(int A[], int n) { if(n <= 1){ return; }//if // 統計個數 int red = 0,white = 0,blue = 0; for(int i = 0;i < n;++i){ if(A[i] == 0){ ++red; }//if
else if(A[i] == 1){ ++white; }//else else{ ++blue; }//else }//for // 重新佈局 for(int i = 0;i < n;++i){ if(red > 0){ A[i] = 0; --red; }//if else if(white > 0){ A[i] = 1; --white; }//else else{ A[i] = 2; } }//for } };

【思路二】

我們可以把陣列分成三部分,前部(全部是0),中部(全部是1)和後部(全部是2)三個部分,每一個元素(紅白藍分別對應0、1、2)必屬於其中之一。

將前部和後部各排在陣列的前邊和後邊,中部自然就排好了。

設定兩個指標begin指向前部的末尾的下一個元素(剛開始預設前部無0,所以指向第一個位置),end指向後部開頭的前一個位置(剛開始預設後部無2,所以指向最後一個位置),然後設定一個遍歷指標current,從頭開始進行遍歷。

(1)若遍歷到的位置為1,則說明它一定屬於中部,根據總思路,中部的我們都不動,然後current向前移動一個位置。

(2)若遍歷到的位置為0,則說明它一定屬於前部,於是就和begin位置進行交換,然後current向前移動一個位置,begin也向前移動一個位置(表示前邊的已經都排好了)。

(3)若遍歷到的位置為2,則說明它一定屬於後部,於是就和end位置進行交換,由於交換完畢後current指向的可能是屬於前部的,若此時current前進則會導致該位置不能被交換到前部,所以此時current不前進。而同1),end向前移動一個位置。

   /**------------------------------------
    *   日期:2015-02-04
    *   作者:SJF0115
    *   題目: Sort Colors
    *   網址:https://oj.leetcode.com/problems/sort-colors/
    *   部落格:
    ---------------------------------------**/
   class Solution {
    public:
        void sortColors(int A[], int n) {
            int begin = 0,end = n-1,cur = 0;
            while(cur <= end){
                if(A[cur] == 0){
                    swap(A[begin],A[cur]);
                    // 指向排序0末尾的下一個位置
                    ++begin;
                    // 向前遍歷
                    ++cur;
                }//if
                else if(A[cur] == 1){
                    ++cur;
                }//else
                else{
                    swap(A[end],A[cur]);
                    // 指向排序2開頭的前一個位置
                    --end;
                }//else
            }//for
        }
    };

【思路三】

用三個變數記錄red,white,blue的下標位置。起始下標都為-1

如果A[i] == 0 ,插入red對white blue有影響,blue先整體向後移動一位,white再整體向後移動一位,如果不移動,前面插入的資料就會覆蓋已有的。

如果A[i] == 1,插入white對blue有影響,blue整體向後移動一位。

A[i] == 2,直接插入blue

  /**------------------------------------
    *   日期:2015-02-03
    *   作者:SJF0115
    *   題目: 75.Sort Colors
    *   網址:https://oj.leetcode.com/problems/sort-colors/
    *   結果:AC
    *   來源:LeetCode
    *   部落格:
    ---------------------------------------**/
    class Solution {
    public:
        void sortColors(int A[], int n) {
            if(n <= 1){
                return;
            }//if
            int red = -1,white = -1,blue = -1;
            for(int i = 0;i < n;++i){
                // 插入red對white blue有影響
                if(A[i] == 0){
                    // blue整體向後移動一位
                    A[++blue] = 2;
                    // white整體向後移動一位
                    A[++white] = 1;
                    // 插入red
                    A[++red] = 0;
                }//if
                // 插入white blue受到影響
                else if(A[i] == 1){
                    // blue整體向後移動一位
                    A[++blue] = 2;
                    // 插入white
                    A[++white] = 1;
                }//else
                // 插入blue對其他沒有影響
                else{
                    // 插入blue
                    A[++blue] = 2;
                }//else
            }//for
        }
    };