第K个排列组合

描述:给定一个集合set={1,2,……,n}。按字典序递增的顺序求第K个排列组合。

输入:{1,2,3},K=2。

输出:{1,3,2}。

思路一:已知求下一个排列组合方法:next_permutation,先将集合元素按照递增排序,循环调用K-1次next_permutation,即可得到第K个排列。但是若K较大接近n!时,则会耗时过长。

class Solution{
public:
	string k_thPermutaion(int A[],int n,int k)
	{
		sort(A,A+n);
		string s;
		for(int i=0;i<n;i++)
		s+=A[i]+'0';
		for(int i=0;i<k-1;i++)
		next_permutation(s.begin(),s.end();
		return s;
	}
}; 
思路二:利用康托展开的逆序思想求解。

康托展开:X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0!,其中a[i]为当前元素在未使用元素中是排在第几个(从0开始)。康托展开用来确定按照字典序递增当前排列之前排列组合的数量。如:已知set={1,2,3}。当前排列为312,从左至右遍历排列元素。a[3]=2,因为当前元素3在未使用元素中{1,2,3}排第二个(从0开始)。a[2]=0,因为当前元素1在未使用元素中{1,2}排第零个(从0开始)。a[1]=0,因为当前元素2在未使用元素中{2}排第零个(从0开始)。因此X=2*(3-1)!+0*(2-1)!+0*(1-1)!=4,表示排列312之前还有四个字典序更小的排列,分别是123,132,213,231。因此我们可以通过康托展开的逆展开来确定当前第K个排列。

康托展开的逆展开:求解字典序递增的全排列中第K个排列。X=K-1,表示前面有K-1个字典序更小的排列。K-1=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0!。可使用辗转相除法分别确定a[n],……,a[1]。如:已知set={1,2,3,4}。求第10个排列(10<4!)。

10/(3!)=1  余  4  a[3]=1,即当前元素是未使用元素{1,2,3,4}中的第一个元素(从0开始)2,则第一个元素为2

4/(2!)  =1  余  0  a[2]=1,即当前元素是未使用元素{1,3,4}中的第一个元素(从0开始)3,则第二个元素为3

0/(1!)  =0  余  1  a[1]=0,即当前元素是未使用元素{1,4}中第0个元素(从0开始),则第三个元素为1

1/(0!)  =0  余  0  a[0]=0,即当前元素是未使用元素{4}中第0个元素(从0开始),则第四个元素为4

则第10个排列为2314。时间复杂度为线性,空间复杂度为线性。

class Solution{
public:
	string k_thPermutaion(int A[],int n,int k)
	{
		sort(A,A+n);
		string s;
		for(int i=0;i<n;i++)
		s+=A[i]+'0';
		string res;
		k--;
		for(int i=n-1;i=1;i--)
		{
			int tmp=k/fun(i);
			res+=s[tmp];
			s.erase(s.begin()+tmp);
			k%=fun(i);
        }
        res+=s[0];
        return res;
		
	}
private:
	int fun(int i)
	{
		if(i==0)return 1;
		else
		return i*fun(i-1);
	}
}; 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值