编程:假设有n个人进行排名,允许并列排名,名次并列人的不同顺序算一种,总共有多少种排名?

疯狂游戏笔试一道有趣的编程题:排名问题

题目描述

假设有n个人进行排名,允许并列排名,名次并列人的不同顺序算一种,总共有多少种排名?
例:n=2,输出3,有:a>b,a<b,a=b。

解题思路

这里用到的是动态规划的方法,当然也可以用递归,但是递归计算复杂度高,所以还是用动态规划吧。不了解递归和动态规划区别的自行百度。

首先假设有j个人,名次的个数为i(1 <= i <= j),当i = 1时,j个人排名一样,当i = j时,j个人没有重复的名次,定义f(i,j)为j个人i个名次的排名个数。我们从简单开始想,首先1个人的时候,只有1种排名方式,即f(1,1) = 1; 两个人的时候相当于在1个人的基础上又加了一个人,而新加入的这个人的名次可能和第一个人的名次相同,也可能不同,即f(1,2) = 1,f(2,2) = 2,因为不同的时候有两种情况,同样3个人的时候是在两个人的基础上新加入一个人,以此类推。。。
总结来说,第一种情况,1 < i < j。j个人有i个名次可以看作是j-1个人新加入1个人,j-1个人的名次有两种情况:(1)i个排名,则新加入的人只能是i个名次中的一个,有i种可能;(2)i-1个名次,则新加入的人只能是新的名次,其可以插入在i-1个名次的任意位置,有i种可能;所以可以得到f(i,j) = i×f(i-1,j-1) + i×f(i,j-1)。
第二种情况,i = 1,所有人名次一样,f(1, j) = 1。
第三种情况,i = j,此时进行全排列即可,f(i, i) = i !。

代码

需要注意的是,程序里的下标是从0开始,所以dp[i][j]实际上是j+1个人有i+1个名次的排名个数。

// 以下只为函数体部分,语言为Java
public int numSort(int n) {
	if(n <= 0)
		return 0;
	if(n == 1)
		return 1;
	int result = 0;
	int[][] dp = new int[n][n];   // dp[i][j]表示j+1个人有i+1种排名的个数
	// 行大于列的地方不考虑
	// 初始化第一行,第二种情况
	for(int i = 0; i < n; i++) {
		dp[0][i] = 1;
	}
	// 初始化对角线,全排列,第三种情况
	for(int i = 1; i < n; i++) {
		dp[i][i] = nFac(i+1);
	}
	// 第一种情况
	for(int i = 1; i < n; i++) {
		for(int j = i+1; j < n; j++) {
			dp[i][j] = (i+1)*dp[i][j-1] + (i+1)*dp[i-1][j-1];
		}
	}
	for(int i = 0; i < n; i ++) {
		result += dp[i][n-1];
	}
	return result;
}
// 求n的阶乘
public int nFac(int n) {
	if(n == 0)
		return 1;
	int result = 1;
	while(n > 0) {
		result *= n;
		n -- ;
	}
	return result;
}

就到这里啦。
2019年7月20日,本人的第一篇博客。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值