天天看點

全排列總結

接觸全排列已經好長時間了,一直沒有抽空總結一下全排列的相關問題,下面來說一下!

  一般地,從n個不同元素中取出m(m≤n)個元素,按照一定的順序排成一列,叫做從n個元素中取出m個元素的一個排列(Arrangement)。特别地,當m=n時,這個排列被稱作全排列(Permutation)。

全排列總結

  特别,當n==m時為全排列的公式!

  左邊是原始排列,右邊是對應的下一個排列。

<code>  1,2,3</code> → <code>1,3,2</code>

<code>  3,2,1</code> → <code>1,2,3</code>

<code>  1,1,5</code> → <code>1,5,1</code>

全排列總結

  如上圖所示,該全排列對應的下一個全排列是和綠色框裡的數字以及紅色框裡的數字有關系的。顯而易見的是紅色框裡的數列已經沒有下一個排列了,因為已經是一個遞減的序列了。為了得到下一個排列,我們将綠色框裡的數字和紅色框裡右邊起第一個比綠色框中數字大的數字交換位置(也就是4 和 5交換位置)。這樣還不是下一個全排列,交換之後紅色框内的序列為7 4 3 2 1 0, 将它變成遞增序列 0 1 2 3 4 7,就得到了下一個全排列。

  因為,一個全排列,末尾的一段區間肯定是遞減的(如上圖的紅色框區間),如果這段區間一直延伸到首部,那麼也就沒有下一個全排列了,否則找到和這段區間最近的一個數字(上圖中綠色框中的數字),然後經過上述的處理就可以得到下一個全排列了。

  the second method 就是先找到綠色框數字的位置(ld), 然後在尋找紅色框中右邊第一個比綠色框中數字大的數字的位置(rd);

  the third method的意思就是從右邊開始尋找第一對(i, j),滿足nums[i]&lt;nums[j], 對應second method中(ld, rd)。該方法沒有用到額外的存儲空間。

  注:算法思想和下一個全排列的思想正好相反,步驟一緻!

  給出排列<code>[1,3,2,3]</code>,其上一個排列是<code>[1,2,3,3]</code>

  給出排列<code>[1,2,3,4]</code>,其上一個排列是<code>[4,3,2,1]</code>

  注:非遞歸,由下一個全排列算法——third方法實作

  注:遞歸思路:一共有nn個位置,然後每個位置枚舉可能出現的數字(注意處理重複數字的情況)

  注:遞歸思路:每一個數,不斷的和後面的數交換位置,每交換一次就會得到一個新的排列

  注:不含重複數字的排列!

  例如,排列[1,4,2]是第2個全排列。

  注:給定 n 和 k,求<code>123..n</code>組成的排列中的第 k 個排列。

  對于 <code>n = 3</code>, 所有的排列是:123, 132, 213, 231, 312, 321.

  如果 <code>k = 4</code>, 第4個排列為,231.

  X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!,ai為整數,并且0&lt;=ai&lt;i(1&lt;=i&lt;=n)

  适用範圍:沒有重複元素的全排列

  找出第16個n = 5的序列(12345)。康托展開隻要O(n)就行 ,下面來說說具體怎麼做:

  根據第一行的那個全排列公式,15 / 4! = 0 …15  =&gt;  有0個數比它小的數是1,是以第一位是1

  拿走剛才的餘數15,用15 / 3! = 2 …3   =&gt;  剩下的數裡有兩個數比它小的是4(1已經沒了),是以第二位是4

  拿走餘數3, 用 3 / 2! = 1 …1   =&gt;  剩下的數裡有一個數比它小的是3,是以第三位是3

  拿走餘數1, 用 1/  1! = 1 …0    =&gt;  剩下的數裡有一個數比它小的是 5(隻剩2和5了),是以第四位是5

  是以排列是 1,4,3,5,2

  思路:next_permutation()本身支援帶重複元素的全排列

  思路:枚舉每個位置肯能出現的數字。

  思路:和 “全排列算法——first”方法類似,唯一不同的是下面代碼中紅色部分。

繼續閱讀