接觸全排列已經好長時間了,一直沒有抽空總結一下全排列的相關問題,下面來說一下!
一般地,從n個不同元素中取出m(m≤n)個元素,按照一定的順序排成一列,叫做從n個元素中取出m個元素的乙個排列(arrangement)。特別地,當m=n時,這個排列被稱作全排列(permutation)。
特別,當n==m時為全排列的公式!
左邊是原始排列,右邊是對應的下乙個排列。
1,2,3
→1,3,2
3,2,1
→1,2,3
1,1,5
→1,5,1
classsolution
}
classsolution
if(ld != -1)
swap(nums[ld], nums[rd]);
//在交換之前,ld位置後面的已經是從大到小排好序的,已經沒有下乙個排列了
sort(nums.begin()+ld+1, nums.end());//
交換之後,將ld後面的數置為最小的排列,從小到大排序
如上圖所示,該全排列對應的下乙個全排列是和綠色框裡的數字以及紅色框裡的數字有關係的。顯而易見的是紅色框裡的數列已經沒有下乙個排列了,因為已經是乙個遞減的序列了。為了得到下乙個排列,我們將綠色框裡的數字和紅色框裡右邊起第乙個比綠色框中數字大的數字交換位置(也就是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]
給出排列
[1,3,2,3]
,其上乙個排列是[1,2,3,3]
給出排列
[1,2,3,4]
,其上乙個排列是[4,3,2,1]
classsolution
};
classsolution
if(ld != -1)
swap(nums[ld], nums[rd]);
//在交換之前,ld位置後面的已經是從小到大排好序的,已經沒有上乙個排列了
//交換之後,將ld後面的數置為最大的排列,從大到小排序
sort(nums.begin()+ld+1, nums.end(), greater());
}if(ld == -1
)
return
nums; }};
classsolution
sort(nums.begin(), nums.end(), greater
());
return
nums;}};
classsolution
if(flag) break
; }
}
return
vv; }
};
class注:遞迴思路:一共有nn個位置,然後每個位置列舉可能出現的數字(注意處理重複數字的情況)solution
while
(next_permutation(nums.begin(), nums.end()));
return
vv; }
};
class注:遞迴思路:每乙個數,不斷的和後面的數交換位置,每交換一次就會得到乙個新的排列solution
for(int i=0; ii)
if(mp[nums[i]])
}
////
vector
int> > permute(vectornums)
};
class注:不含重複數字的排列!solution
for(int i=ld; i<=rd; ++i)
}vector
int> > permute(vectornums)
};
例如,排列[1,4,2]是第2個全排列。
演算法思想請參考:
class注:給定 n 和 k,求solution while(next_permutation(permu.begin(), permu.end()));
//return cnt;
vector
a;int len =a.size();
intcnt[len];
cnt[len-1] = 0
; a.push_back(a[len-1
]);
for(int i=len-2; i>=0; --i)
long
long ans=1, fac=1, c=1
;
for(int i=len-2; i>=0; --i)
ans += (fac*=c++)*cnt[i];
return
ans;}};
123..n
組成的排列中的第 k 個排列。對於
n = 3
, 所有的排列是:123, 132, 213, 231, 312, 321.如果
k = 4
, 第4個排列為,231.x=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!,ai為整數,並且0<=ai適用範圍:沒有重複元素的全排列
找出第16個n = 5的序列(12345)。康托展開只要o(n)就行,下面來說說具體怎麼做:
根據第一行的那個全排列公式,15 / 4! = 0 …15 => 有0個數比它小的數是1,所以第一位是1
拿走剛才的餘數15,用15 / 3! = 2 …3 => 剩下的數里有兩個數比它小的是4(1已經沒了),所以第二位是4
拿走餘數3, 用 3 / 2! = 1 …1 => 剩下的數里有乙個數比它小的是3,所以第三位是3
拿走餘數1, 用 1/ 1! = 1 …0 => 剩下的數里有乙個數比它小的是 5(只剩2和5了),所以第四位是5
所以排列是 1,4,3,5,2
class思路:next_permutation()本身支援帶重複元素的全排列solution
++cnt;}}
}for(int j=1; j<=n; ++j)
if(!use[j])
return
ans;}};
class思路:列舉每個位置肯能出現的數字。solution
while
(next_permutation(nums.begin(), nums.end()));
return
ans;}};
class思路:和 「全排列演算法——first」方法類似,唯一不同的是下面**中紅色部分。solution
for(int i=0; ii)
if(cnt[nums[i]])
}vector
int> > permuteunique(vector &nums)
};
classsolution
if(flag) break
; }
}return
ans;}};
全排列總結
若給你一堆數,讓你輸出他的全排列,可以有以下方式實現,不過各有優點和缺點 1.深度優先搜尋 included include include includeusing namespace std int n int book 100 int ch 100 int kong 100 void dfs ...
全排列總結
馬上藍橋杯省賽了 菜雞又是去當分母的 把一些基礎的演算法都總結一下,當作複習了 首先最簡單的是用stl中的next permutation和prev permutation了 next permutation start,end 是輸出下乙個排列,所以用之前要對陣列進行從小到大排序 void per...
全排列演算法總結
本文同時發布在我的個人部落格 求 n 位的字串的全排列,先確定第 0 位,然後對後面 n 1 位進行全排列,在對 n 1 為進行全排列時,先確定第 1 位,然後對後面的 n 2 位進行全排列.由此得到遞迴函式和遞迴的結束條件。全排列也就是交換位置,到 n 2 位時,就是將 n 2 和 n 1 交換位...