题目要求我们模拟一场淘汰赛,并计算所有比赛的总场次,直到最后只剩下一个获胜队伍。每场比赛有两支队伍参与,比赛结束后,只有一支队伍晋级到下一轮。
关键要点:
-
每轮比赛的队伍数会减少。若当前队伍数是偶数,那么每场比赛将有两支队伍,下一轮会有一半的队伍晋级;若当前队伍数是奇数,则少一支队伍“自动晋级”,剩下的队伍成对进行比赛,最终也会有一半队伍晋级。
-
每轮比赛的场次可以通过队伍数计算,具体为:
- 如果队伍数是偶数,比赛的场次是队伍数除以2(
n / 2)。 - 如果队伍数是奇数,比赛的场次是
(n - 1) / 2,剩下的队伍中有一支“自动晋级”。
- 如果队伍数是偶数,比赛的场次是队伍数除以2(
问题分析
1. 如何模拟每轮比赛?
每轮比赛的处理逻辑分为两种情况:
-
队伍数是偶数:
- 比赛的场次是
n / 2(队伍数除以2),并且晋级的队伍数也会是n / 2。 - 例如,如果队伍数是
4,那么第一轮会进行4 / 2 = 2场比赛,剩下2支队伍晋级。
- 比赛的场次是
-
队伍数是奇数:
- 比赛的场次是
(n - 1) / 2,并且晋级的队伍数是(n - 1) / 2 + 1(多出一支队伍会自动晋级)。 - 例如,如果队伍数是
7,那么第一轮会进行(7 - 1) / 2 = 3场比赛,剩下3 + 1 = 4支队伍晋级。
- 比赛的场次是
2. 直到剩下最后一支队伍
比赛会继续进行,直到剩下最后一支队伍为止。在每一轮中,队伍数都会减少,因此通过不断地计算每一轮的比赛场数并累加,直到只剩下一个队伍为止。
3. 计算总的比赛场数
每轮的比赛场数可以通过上面的规则计算出来,然后将所有轮次的比赛场数加起来,就能得到总的比赛场数。
解题步骤
-
初始化一个变量
totalMatches用于存储总的比赛场数。 -
使用一个循环,不断进行比赛,直到只剩下1支队伍:
- 计算当前轮次的比赛场数,更新
totalMatches。 - 根据队伍数的奇偶性,更新剩余的队伍数。
- 计算当前轮次的比赛场数,更新
-
返回
totalMatches即为所有比赛的总场数。
代码实现
public class Main {
public static void main(String[] args) {
// 测试用例
System.out.println(countMatches(7)); // 输出 6
System.out.println(countMatches(14)); // 输出 13
System.out.println(countMatches(1)); // 输出 0
}
public static int countMatches(int n) {
int totalMatches = 0; // 用于记录总比赛场次
// 当队伍数大于1时,继续进行比赛
while (n > 1) {
if (n % 2 == 0) {
// 队伍数为偶数
totalMatches += n / 2; // 每场比赛有 n / 2 场
n = n / 2; // 晋级的队伍数是 n / 2
} else {
// 队伍数为奇数
totalMatches += (n - 1) / 2; // 每场比赛有 (n - 1) / 2 场
n = (n - 1) / 2 + 1; // 晋级的队伍数是 (n - 1) / 2 + 1
}
}
return totalMatches; // 返回所有比赛的总场数
}
}
代码详细讲解
-
countMatches方法:- 输入:一个整数
n,表示队伍数。 - 输出:一个整数,表示总的比赛场数。
- 输入:一个整数
-
主循环:
- 使用
while (n > 1)循环,表示每轮比赛都在进行,直到队伍数减少到1为止。 - 如果
n是偶数,则每轮比赛有n / 2场,晋级的队伍数也会是n / 2,即n减半。 - 如果
n是奇数,则每轮比赛有(n - 1) / 2场,剩下的一支队伍自动晋级,晋级的队伍数是(n - 1) / 2 + 1,也就是队伍数减去一半,再加上一支自动晋级的队伍。
- 使用
-
更新
totalMatches:- 每次计算当前轮的比赛场数并加到
totalMatches中,直到队伍数减少到1为止。
- 每次计算当前轮的比赛场数并加到
-
返回结果:
- 最终返回累计的
totalMatches,即所有比赛的总场数。
- 最终返回累计的
例子分析
例子1:n = 7
- 第一轮:7个队伍(奇数),进行
(7-1)/2 = 3场比赛,剩下3 + 1 = 4支队伍晋级。 - 第二轮:4个队伍(偶数),进行
4 / 2 = 2场比赛,剩下 2 支队伍晋级。 - 第三轮:2个队伍(偶数),进行
2 / 2 = 1场比赛,剩下 1 支队伍晋级。 - 总场数:
3 + 2 + 1 = 6。
例子2:n = 14
- 第一轮:14个队伍(偶数),进行
14 / 2 = 7场比赛,剩下 7 支队伍晋级。 - 第二轮:7个队伍(奇数),进行
(7-1)/2 = 3场比赛,剩下3 + 1 = 4支队伍晋级。 - 第三轮:4个队伍(偶数),进行
4 / 2 = 2场比赛,剩下 2 支队伍晋级。 - 第四轮:2个队伍(偶数),进行
2 / 2 = 1场比赛,剩下 1 支队伍晋级。 - 总场数:
7 + 3 + 2 + 1 = 13。
例子3:n = 1
- 只有1支队伍,不需要进行任何比赛,返回 0 场。
时间复杂度
每轮比赛都会使队伍数量减少一半,因此循环的次数是与队伍数的对数成正比。具体地,最多需要 O(log n) 次循环,其中 n 是初始的队伍数。
- 在每轮循环中,计算比赛场数和更新队伍数都是常数时间的操作。
- 因此,整个算法的时间复杂度是
O(log n)。
总结
通过这个问题的解析,我们可以看出,虽然问题表面上是关于比赛的模拟,但实际上是一个基于队伍数不断减少的过程。通过每轮比赛后计算比赛场数,并根据队伍数的奇偶性更新队伍数,最终计算出总的比赛场数。