【有重複數字的全排列_求法 & 計算個數】

輸入一組數字(可能包含重複數字),輸出其所有的排列方式。

樣例
輸入:[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) = 22,33,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]; 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章