全排列演算法
一、無重複數全排列
方法①:
1. 原理
假設待排序列為
a
=
{
a
1
,
a
2
,
a
3
,
.
.
.
,
a
n
}
a = \{a_1,a_2,a_3,...,a_n\}
a={a1,a2,a3,...,an},對應的全排列記為
P
e
r
m
u
(
1
,
n
)
Permu(1, n)
Permu(1,n),表示索引從
1
1
1到
n
n
n的陣列成序列的全排列。它是一個集合,集合中的每個元素是一種排列。比如對於序列
{
1
,
2
,
3
}
\{1,2,3\}
{1,2,3},
P
e
r
m
u
(
1
,
3
)
=
{
{
1
,
2
,
3
}
,
{
1
,
3
,
2
}
,
{
2
,
1
,
3
}
,
{
2
,
3
,
1
}
,
{
3
,
1
,
2
}
,
{
3
,
2
,
1
}
}
Permu(1,3)=\{ \{1,2,3 \}, \{1,3,2 \}, \{2,1,3 \}, \{2,3,1 \}, \{3,1,2 \}, \{3,2,1 \} \}
Permu(1,3)={{1,2,3},{1,3,2},{2,1,3},{2,3,1},{3,1,2},{3,2,1}}
一般的,對於長度為
n
n
n的序列,
P
e
r
m
u
(
1
,
n
)
=
{
{
a
1
,
P
e
r
m
u
a
1
(
2
,
n
)
}
,
{
a
2
,
P
e
r
m
u
a
2
(
2
,
n
)
}
,
.
.
.
,
{
a
n
,
P
e
r
m
u
a
n
(
2
,
n
)
}
}
Permu(1,n)=\{ \{a_1, Permu_{a_1}(2,n)\}, \{a_2, Permu_{a_2}(2,n)\}, ...,\{a_{n}, Permu_{a_n}(2,n)\} \}
Permu(1,n)={{a1,Permua1(2,n)},{a2,Permua2(2,n)},...,{an,Permuan(2,n)}}
因此,可以用遞迴求解。當遞迴到待排序列只有一個數的時候,排列即為該數,可以返回。所以遞迴終止條件為:
P
e
r
m
u
a
i
(
n
,
n
)
=
a
i
Permu_{a_i}(n,n)=a_i
Permuai(n,n)=ai
2. 實現思路如下:
- 觀察發現, P e r m u ( 1 , n ) Permu(1,n) Permu(1,n)中的每一種排列,實際上是分別將每一個數都作為序列的第一個數,然後剩下的 ( 2 , n ) (2,n) (2,n)的序列再交給遞迴函式去排列。所以我們可以進行 n n n次迴圈,每次將索引為 i i i的數置換到第1個位置
- 每交換一次,就遞迴進行 P e r m u ( 2 , n ) Permu(2,n) Permu(2,n)的排列。而 P e r m u ( 2 , n ) Permu(2,n) Permu(2,n)的操作與第1步類似
- 排序完後,再交換回來
3. 程式碼:
int a[] = {1, 2, 3};
void permu(int begin, int end)
{
if(begin == end) // 待排序列只有一個數
{
for(int i = 0; i < 3; i ++ )
cout << a[i] << " ";
cout << endl;
return ;
}
for(int i = begin; i <= end; i ++ ) // 進行序列長度次迴圈
{
swap(begin, i); // 每次迴圈,將索引為i的數作為第1個數
permu(begin + 1, end);
swap(i, begin);
}
}
int main()
{
permu(1, n);
return 0;
}
這個演算法中,“排列”的這個動作,實際上是交換操作完成的。若干次交換操作組合在一起,就完成了一次排列。
方法②
這個方法也是我之前直接經常用的。
1.原理
一個排列可以看做:在這 n n n個位置的每一個位置,放一個 1 1 1到 n n n中沒有放過的數。所以可以對位置進行 d f s dfs dfs。每次在當前位置,遍歷所有的數,找到沒放過的數放入當前位置,然後 d f s dfs dfs下一個位置。
2. 程式碼
原理比較簡單,就直接貼程式碼了:
int a[] = {1, 2, 3};
int pos[3]; // 排列陣列。放的數放到該陣列中
bool st[3]; // 用來判斷第i個位置的數有沒有被放過
void dfs(int step)
{
if(step == 3) // 遞迴了最後一個位置的後一個,即所有的數都放完了,一個排列已經形成,可以返回。
{
for(int i = 0; i < 3; i ++ )
cout << pos[i] << " ";
cout << endl;
return ;
}
for(int i = 0; i < 3; i ++ )
{
if(!st[i]) // 沒有被放過
{
st[i] = true;
pos[step] = i; // 將i放入當前位置step
dfs(step + 1);
st[i] = false; // 恢復現場
}
}
}
int main()
{
dfs(1); // 從第1個位置開始dfs
return 0;
}
相關文章
- 演算法——全排列演算法
- 【Algorithm】全排列演算法Go演算法
- 全排列及相關擴充套件演算法(二)——求字典序下一組排列及全排列演算法套件演算法
- LeetCode46 回溯演算法求全排列,這次是真全排列LeetCode演算法
- 前端電商 sku 的全排列演算法前端演算法
- 字串全排列字串
- Leetcode——46. 全排列LeetCode
- leetcode:全排列(java回溯)LeetCodeJava
- LeetCode系列46—全排列LeetCode
- 【LeetCode】46. 全排列LeetCode
- LeetCode-046-全排列LeetCode
- Day 28 | 491.遞增子序列 、46.全排列、 47.全排列 II
- 遞迴-*全排列問題遞迴
- JavaScript陣列元素全排列JavaScript陣列
- LeetCode-047-全排列 IILeetCode
- js陣列全排列問題JS陣列
- 有重複元素的全排列
- 藍橋杯全排列專題
- 位右移 字母大小寫全排列
- 程式碼隨想錄演算法訓練營day29 | leetcode 491. 非遞減子序列、46. 全排列、47. 全排列 II演算法LeetCode
- 遞迴解決全排列問題遞迴
- 全排列價值(數學問題)
- 【leetcode】60. Permutation Sequence 全排列的第k位序的排列形式LeetCode
- 從基礎講全排列(Java實現)Java
- LeetCode 45跳躍遊戲&46全排列LeetCode遊戲
- Python語言的全排列怎麼提速?Python
- 藍橋杯之帶分數(全排列+暴力)
- 回溯法解決全排列問題總結
- 2014省賽---六角填數(填空)(全排列)
- 從1到n的全排列(深度優先搜尋)
- 全排列的實現之遞迴版與迭代版遞迴
- 遞迴演算法實踐---實現排列組合遞迴演算法
- 逆序排列
- 排列 題解
- 排列組合
- [MATLAB]排列大小Matlab
- JavaScript字串逆序排列JavaScript字串
- AUTOCAD——弧形文字排列