比赛配对问题 | 豆包MarsCode AI刷题

117 阅读5分钟

题目要求我们模拟一场淘汰赛,并计算所有比赛的总场次,直到最后只剩下一个获胜队伍。每场比赛有两支队伍参与,比赛结束后,只有一支队伍晋级到下一轮。

关键要点:

  1. 每轮比赛的队伍数会减少。若当前队伍数是偶数,那么每场比赛将有两支队伍,下一轮会有一半的队伍晋级;若当前队伍数是奇数,则少一支队伍“自动晋级”,剩下的队伍成对进行比赛,最终也会有一半队伍晋级。

  2. 每轮比赛的场次可以通过队伍数计算,具体为:

    • 如果队伍数是偶数,比赛的场次是队伍数除以2(n / 2)。
    • 如果队伍数是奇数,比赛的场次是(n - 1) / 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. 计算总的比赛场数

每轮的比赛场数可以通过上面的规则计算出来,然后将所有轮次的比赛场数加起来,就能得到总的比赛场数。

解题步骤

  1. 初始化一个变量 totalMatches 用于存储总的比赛场数。

  2. 使用一个循环,不断进行比赛,直到只剩下1支队伍:

    • 计算当前轮次的比赛场数,更新 totalMatches
    • 根据队伍数的奇偶性,更新剩余的队伍数。
  3. 返回 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;  // 返回所有比赛的总场数
    }
}

代码详细讲解

  1. countMatches 方法

    • 输入:一个整数 n,表示队伍数。
    • 输出:一个整数,表示总的比赛场数。
  2. 主循环

    • 使用 while (n > 1) 循环,表示每轮比赛都在进行,直到队伍数减少到1为止。
    • 如果 n 是偶数,则每轮比赛有 n / 2 场,晋级的队伍数也会是 n / 2,即 n 减半。
    • 如果 n 是奇数,则每轮比赛有 (n - 1) / 2 场,剩下的一支队伍自动晋级,晋级的队伍数是 (n - 1) / 2 + 1,也就是队伍数减去一半,再加上一支自动晋级的队伍。
  3. 更新 totalMatches

    • 每次计算当前轮的比赛场数并加到 totalMatches 中,直到队伍数减少到1为止。
  4. 返回结果

    • 最终返回累计的 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)

总结

通过这个问题的解析,我们可以看出,虽然问题表面上是关于比赛的模拟,但实际上是一个基于队伍数不断减少的过程。通过每轮比赛后计算比赛场数,并根据队伍数的奇偶性更新队伍数,最终计算出总的比赛场数。