康拓排列的自我總結 以及全排列的遞迴非遞迴演算法

2021-07-28 15:37:13 字數 2338 閱讀 7528

寫了幾個關於全排列的東西,然後就接觸到了康拓排列。之前對於全排列的非遞迴演算法耿耿於懷,乙隻不能找到好的方式。現在好了,有了康拓,什麼都解決了。

我們先來看乙個簡單的例子,就是如何遞迴的求全排列。

private static void recursionpermutation(string s, int k) 

system.out.println();

} for(int i=k;i

上述就是求全排列的遞迴演算法了,那麼這裡引入乙個概念,就是康拓排列,什麼是康拓排列呢?乙個陣列,求它的全排列,然後按照從小到大的順序(這個可以是字典順序啊,或者你定義的其他順序都行)排好,那麼這就是康拓排列。比如,它的康拓排列就是,,,,,。

康拓排列有乙個前提是裡面的元素不能有重複的!

這是乙個經典問題,前面已經減了什麼事康拓排列了,那麼給你乙個排列,讓你求它的下乙個排列是什麼,這個演算法應該怎麼寫呢?比如上述例子,的下乙個排列是。

這個例子的演算法如下,不多說,自己慢慢看。

public class nextpermutation ;

int next = nextpermutation(nums);

system.out.println(arrays.tostring(next));

} public static int nextpermutation(int nums)

} //交換兩個元素

swap(nums,i,partitionnumbersite);

//逆序排序

for(int j=pivot,k=nums.length-1;j

康拓排列有乙個典型的應用就是判斷乙個排列的位置,給你乙個排列),那麼這個排列肯定是第乙個啊。那麼對於四個數字的呢?5個數字的,它有在哪乙個呢?

這個的演算法的思想如下:

先了解什麼是康拓展開

形如下式的炸開叫做康拓展開,

x=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!

ai為整數,並且0<=ai於是我們建立3個桶,我們知道3個桶裡面已經放好數字了,分別是3,2,1.現在我們想知道這個數字是第幾大的。怎麼辦呢,我們看第乙個桶,第乙個桶中的數字是3,但是第乙個桶我們知道如果你來放的話,是可以放1,2,3三個數字的,那麼這裡面比三小的數字有1,和 2連個,於是,由1或者2開頭的全排列都比3開頭的全排列要小(100多肯定小於300多啊),於是我們知道由1開頭的有1*2!(階乘)個,由2開頭的有1*2!(階乘)個,所以,這裡有2*2!個。再看第二個桶,同理,第二個桶被放了2,此時第乙個桶已經放好3了,所以第二個桶你來放的話,只能放2和1。我們知道,32*肯定比31*要大,而滿足這個條件的,只有1*1!(階乘)種。最後第三個桶,已經沒有比它小的了,所以只能乘以0了。於是就是2*2!+1*1!+0*0!=5.所以這個排列是第6大的(別忘記加1)

再舉個例子:1324是排列數中第幾個大的數:第一位是1小於1的數沒有,是0個,0*3!,第二位是3小於3的數有1和2,但1已經在第一位了,所以只有乙個數2,1*2! 。第三位是2小於2的數是1,但1在第一位,所以有0個數,0*1!,所以比1324小的排列有0*3!+1*2!+0*1!=2個,1324是第三個大數。

**非常簡單,如下

public static int cantor(int nums)

}result+=temp*factorial(length-i-1);

} return result+1;

}

這個題目有兩種做法,一種是執行k-1次nextpermutation,另外一種就是使用康托排列了。重點講康托排列。

如何找出第16個(按字典序的)的全排列?

1. 首先用16-1得到15

2. 用15去除4! 得到0餘15

3. 用15去除3! 得到2餘3

4. 用3去除2! 得到1餘1

5. 用1去除1! 得到1餘0

有0個數比它小的數是1,所以第一位是1

有2個數比它小的數是3,但1已經在之前出現過了所以是4

有1個數比它小的數是2,但1已經在之前出現過了所以是3

有1個數比它小的數是2,但1,3,4都出現過了所以是5

最後乙個數只能是2

所以排列為1 4 3 5 2

下面是兩種方法的**:

private static void getpermutationbynext(int i, int j) 

//別忘記最後乙個元素

result[n-1]=list.get(0);

return result;

}

康拓拓展和逆拓展解決全排列問題

在解決排列問題時,一般有以下問題 給你乙個排列,問你是第幾個排列 給你乙個排列,問下乙個排列是多少 給你乙個排列,問前乙個排列是多少 給你乙個數i,問第i個排列是多少 一般暴力的話使用遞迴加回溯都能解決,但是時間複雜福比較高,遞迴多了棧也會溢位。這裡使用康拓展開的思想,具體思路。看不懂沒關係,繼續看...

關於全排列問題的總結(康托展開)

今天做usaco上一道題的時候用到了這個東西,當時覺得麻煩直接用map寫了,然後仔細研究了一下,康托展開與其逆展開,個人覺得會在節省空間和表示狀態上有比較大的幫助。先來正展開吧,即給定排列序列,求是第幾個排列,看序列中的第k位,假設序列長度為n,那麼,k位之後的各位數全排列有 n k 種,然後看k之...

康托展開 全排列的本質

參考鏈結 x a n n 1 a n 1 n 2 a i i 1 a 1 0 1.求乙個排列是原排列的按字典序的第幾個排列。include include using namespace std int fac 階乘 intcantor int a,int n x fac n i 1 smaller...