1. 程式人生 > >Permutation遞迴解法

Permutation遞迴解法

permutation的題一般來說是給一個序列,然後要求得到所有的不同permutation。對於這類題需要分下面這幾種情況

1. 從input的內容來分:有2種,分別是有duplicate和no duplicate的

解法:這兩種情況的結果其實有有同一個特性:在同一個position,同一種字母只能出現一次。只不過沒有duplicate的情況下不需要額外處理就可以達到這個效果。針對有duplicate的情況,我們在每次的recursion中都需要設定一個set來儲存這個位置已經使用過的數字或者字母。見如下的tree:

example: input is: 1, 1, 2
on each recursion level, we skip the duplicate number
                /       |      \
               1       [1]重複  2               n
             /  \     / \      |  \
            1    2   1   2     1  [1]重複       n * (n - 1)
           /    /   /   /      |   |
          2    1   2   1       1   1            n * (n - 1) * (n - 2)

time: O(n!)
space: O(n)
1 1 2
1 2 1
2 1 1

2. 從input的type來分:

1. 可以是array

2. 可以是list

3. 也可以是個string

區別:這裡的區別在於是否能夠in place操作其中的element。比如array就可以快速的swap裡面的element,這時候我們的permutation就可以使用swap的方式。但是string是沒有辦法這樣操作的。所以如果後面2種情況出現又想要做in place的話,最好是重新建立一個array來儲存其中的內容。這樣也可以避免List的get()的時間複雜度不恆定的問題。string可以使用toCharArray()來得到char的array

3. 從output的要求來分:

1是不用output,就print出來。

2是要返回一個List<string>。

3是要返回一個List<List<Integer>>

區別: 1.如果不用output,我們可以寫一個函式把那個array或者temp arraylist中的內容打印出來。這個問題一般不大

2. 如果需要返回一個string,那麼input一般來說是一個string或者是char array.這類的做法也比較方便,用swap的方法最後rst.add(new String(input))就可以實現

3. 需要注意的是如果要求返回的值是List<List<Integer>>,那麼最後加入rst的那步一定是需要一個一個把array中的數字新增到最後的list中去的。最好是這樣做,可以保證不會出問題。因為並不是很麻煩而且不會出現想用現成函式用錯的情況。畢竟list中的是object而array中的可能是permitIve type

這題雖然也有permutation,實際上和permutation關係不大。讓求得是lexicographically next greater permutation of numbers. lexicographically大的意思就是說對這個數字的所有permutations進行從小到大額排序後隨便抽一個出來問這個的下一個是什麼。比如說:123的排序有:

123,132, 312, 321, 213, 231

對這些數字進行排序之後得到:123, 132, 213, 231, 312, 321

問132的下一個lexicographically大的數字是哪個?答案是213

所以我們可以看到光問下一個是什麼,我們可以把所有的permutation都解出來,然後排序,然後找到下一個是什麼。但是這樣操作的話時間複雜度太高。所以我們還是得另闢蹊徑。對數字進行觀察可以發現,我們想要做得是儘量讓這個數字而的右邊的位數變大的同時也能讓整個數字的大小變大。我們的做法是把digits分成2塊。每次看一個位數1【3】2。假如3需要被置換掉的話,我們只在3的右邊看能不能找到數字讓它變大。如果能夠的話,就保證了左邊那塊權重更重的不會受到影響。所以針對132

先看3, 發現右邊的2只能把它變小,不行。continue

再看1,發現右邊可以找到數字讓它變大,那麼找到右邊比1大的最小的數字2, 然後進行置換得到213,後面還要進行的一個操作是把後【13】進行從小到大的排序,使得右邊的的確是能得到的最小的數。通過這樣的過程,我們保證了儘量使得數字變大的同時讓其變大的幅度最小。