1. 程式人生 > >面試常考演算法題(二)--荷蘭國旗問題

面試常考演算法題(二)--荷蘭國旗問題

面試常考演算法題(二)–荷蘭國旗問題

荷蘭國旗問題是面試中常考的一個題目,涉及到的思想並不是很複雜.

荷蘭國旗問題

題目

給定一個數組arr,和一個數num,請把小於num的數放在陣列的左邊,等於num的數放在陣列的中間,大於num的數放在陣列的右邊。
要求額外空間複雜度O(1),時間複雜度O(N)

問題解析

最差解法

這個問題如果不考慮時間複雜度和空間複雜度的話,最簡單的解法自然是使用輔助陣列,對當前陣列資料進行分類以後複製回原陣列,程式碼如下:

   
   public static int[] terriblePartition(int[] arr, int num) {
        if
(arr == null || arr.length < 2){ return arr; } int[] temp = new int[arr.length]; int m = -1; int n = arr.length ; //設定兩個指標,分別指向temp陣列的最前面和最後面,將小於num的資料放在前部分,大於num的資料放在後部分 for (int i = 0; i < arr.length; i++) { if (arr[i] <
num) { temp[++m] = arr[i]; } else if (arr[i] > num){ temp[--n] = arr[i]; } } //等於num的陣列資料放在中間 for (int i = m + 1; i < n; i++) { temp[i] = num; } //複製temp陣列資料到arr陣列 copyArr(arr, temp)
; //返回等於num資料的位置 return new int[]{m + 1, n - 1}; } private static void copyArr(int[] arr, int[] temp) { for (int i = 0; i < temp.length; i++) { arr[i] = temp[i]; } }

這個答案除非題目不要求並且時間不足夠思考更優秀的演算法,不然不建議使用此方法,這種解法一般僅用作比較器.

優秀一點的解法

那麼如何在上述方法上進行優化呢,其實本質所使用的思想和上述程式碼思想一致.知道讀者未必對上面的程式碼感興趣,這裡我來通過一個實際陣列[4, 5, 2, 8, 1, 9, 6, 11]進行圖解一下:
imagepng

imagepng

imagepng

imagepng

imagepng

程式碼

  public static int[] partition(int[] arr, int num) {
        if(arr == null || arr.length < 2){
            return arr;
        }
        int less = -1;
        int more = arr.length;
        int i = 0;
        while (i < more) {
            if (arr[i] < num) {
                swap(arr, ++less, i++);
            } else if (arr[i] > num) {
                swap(arr, --more, i);
            }else {
                i++;
            }
        }
       //返回等於num資料的位置
        return new int[] { less + 1, more - 1 };
    }

    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

後記

這篇文章到這裡可以說已經結束了,這個問題中的思想在快速排序中可以得到應用,可以用荷蘭國旗問題來改進快速排序
使其時間複雜度變為O(N*logN),額外空間複雜度O(logN),這個問題將在下一篇文章快速排序中講.必須要注意的一點是,荷蘭國旗問題的解法其實是不穩定的,會改變原陣列本可以不改變順序的資料的相對順序.比如[0 9 7 4 4 ]陣列最後得到的結果是[0 4 4 7 9 ],陣列中的兩個4實際上交換了位置.

百度百科給出穩定演算法的定義如下:

假定在待排序的記錄序列中,存在多個具有相同的關鍵字的記錄,若經過排序,這些記錄的相對次序保持不變,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序後的序列中,r[i]仍在r[j]之前,則稱這種排序演算法是穩定的;否則稱為不穩定的。