【有重复数字的全排列_求法 & 计算个数】

14 篇文章 0 订阅
3 篇文章 0 订阅
输入一组数字(可能包含重复数字),输出其所有的排列方式。

样例
输入:[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]; 
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值