輸入一組數字(可能包含重複數字),輸出其所有的排列方式。
樣例
輸入:[1,1,1,2]
輸出:
[
[1,1,1,2],
[1,1,2,1],
[1,2,1,1],
[2,1,1,1],
]
最暴力的解法:
- 當重複的數字不存在,做正常的全排列,最後在結果集中去重即可。
另外一種解法:
- 找重複數字在排列的中的規律
例如:
輸入:[1,1,1,2,3] 裏面的重複數字是三個 1,考慮三個 1 的順序
- - - - -
1 1 1 - - [1,1,1,2,3]、[1,1,1,3,2]
1 1 - 1 -
1 1 - - 1
1 - 1 1 -
1 - 1 - 1
1 - - 1 1
- 1 1 1 -
- 1 1 - 1
- 1 - 1 1
- - 1 1 1
這就是三個 1 的所有情況。會感覺到有一種最外層的 1 慢慢的壓到最右邊
實際上,當確定了 1 的位置的時候,下一個 1 一定得在上一個 1 的右邊,保證一個相對位置。
如果當 1 放完了,就算後面還有其他重複的數字,也只需要按照放 1 的規則在空的位置上放就行了(如果沒有重複那就是自己隨便跑到哪個空位都可以)。
而此時所有情況的個數就是:C(5, 2) = 10 (五個位置選三個放 1 ),因爲剩下的兩個位置留個了 [2, 3] 他們在空位上選相當於 A(2, 2) = 2(2,3和3,2是不一樣的)。
所以不重複的全排列個數 = C(5, 2) * A(2, 2) = 20 種
求全部情況的部分代碼:
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
vector<vector<int>> permutation(vector<int>& nums) {
path.resize(nums.size());
sort(nums.begin(), nums.end());
dfs(nums, 0, 0, 0);
return ans;
}
void dfs(vector<int>& n, int u, int start, int state){
if(u == n.size()){
ans.push_back(path);
return;
}
if(!u || n[u] != n[u - 1])start = 0;//如果是第一個數,或者,與前一個數不相等
for (int i = start; i < n.size(); i ++ )
if(!(state >> i & 1)){//第i位爲 0,可放數據
path[i] = n[u];
dfs(n, u + 1, i + 1, state + (1 << i));//將第i位置爲1
}
}
};
求C(n, m) 代碼(楊輝三角):
#include<bits/stdc++.h>
using namespace std;
const int N = 100;
int f[N][N];
int main(){
for(int i = 0; i < N; i++ ){
for(int j = 0; j <= i; j++ ){
if(!j)f[i][j] = 1;//第一列時,都爲1
else f[i][j] = f[i - 1][j] + f[i - 1][j - 1];//其他則爲兩數相加
}
}
int n,m;
cin >> n >> m;
cout << "C(n, m):" << f[n][m];