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

108 阅读3分钟

在深入探讨 “比赛配对问题” 时,我们面临的核心挑战是依据给定的参赛队伍数量n,精准地计算出整个比赛历程中所发生的配对次数,直至最终唯一的获胜队伍脱颖而出。

首先,我们来看解题思路。由于赛制规定了队伍数量为偶数和奇数时不同的配对与晋级方式,所以我们可以采用递归的思想来解决这个问题。从初始的 n 支队伍开始,不断地根据队伍数量的奇偶性进行配对和晋级操作,并累计每一轮的配对次数,直到最后只剩下一支队伍。在每一轮中,如果队伍数是偶数,那么配对次数就是队伍数的一半,并且下一轮的队伍数也变为当前队伍数的一半;如果队伍数是奇数,配对次数为 (n - 1) / 2,下一轮队伍数则是 (n - 1) / 2 + 1。通过不断地重复这个过程,就能得到总的配对次数。

下面详细解析代码:

class Main {
    public static int solution(int n) {
        int count = 0;
        count = cauculate(n, count);
        return count;
    }

    private static int cauculate(int n, int count) {
        // 递归终止条件,当只剩下一支队伍时,返回当前累计的配对次数
        if (n == 1) {
            return count;
        }
        // 如果队伍数为偶数
        if (n % 2 == 0) {
            // 累计本轮的配对次数,即 n/2
            count += n / 2;
            // 更新下一轮的队伍数为 n/2
            n = n / 2;
            // 递归调用计算下一轮的配对情况
            return cauculate(n, count);
        } else {
            // 如果队伍数为奇数,累计本轮配对次数为 (n - 1) / 2
            count += (n - 1) / 2;
            // 更新下一轮的队伍数为 (n - 1) / 2 + 1
            n = (n - 1) / 2 + 1;
            // 递归调用计算下一轮
            return cauculate(n, count);
        }
    }

    public static void main(String[] args) {
        // 测试示例
        System.out.println(solution(7) == 6);
        System.out.println(solution(14) == 13);
        System.out.println(solution(1) == 0);
    }
}

在 solution 方法中,首先初始化一个变量 count 为 0,用于累计配对次数,然后调用 cauculate 方法并传入初始的队伍数量 n 和 count

在 cauculate 方法中,首先判断是否只剩下一支队伍,如果是,则直接返回当前的 count。接着判断队伍数量 n 的奇偶性,如果是偶数,就按照偶数队伍的赛制规则,将本轮的配对次数 n / 2 累加到 count 中,并更新下一轮的队伍数为 n / 2,然后递归调用 cauculate 方法继续计算下一轮。如果队伍数是奇数,同样按照奇数队伍的赛制规则,累计配对次数为 (n - 1) / 2,更新下一轮队伍数为 (n - 1) / 2 + 1,再递归调用。

例如,当 n = 7 时,第一轮队伍数为奇数,配对次数为 (7 - 1) / 2 = 3,下一轮队伍数变为 (7 - 1) / 2 + 1 = 4。第二轮队伍数为偶数,配对次数为 4 / 2 = 2,下一轮队伍数变为 4 / 2 = 2。第三轮队伍数为偶数,配对次数为 2 / 2 = 1,下一轮队伍数变为 2 / 2 = 1,此时满足递归终止条件,返回总的配对次数 3 + 2 + 1 = 6

最后,我们来分析一下时间复杂度和空间复杂度。从时间复杂度来看,由于每次递归都会将队伍数量大致减半,所以总的时间复杂度接近O (log n)。在空间复杂度方面,由于采用了递归,递归调用栈的深度最多为 log n,所以空间复杂度也为 O (log n)。这种递归的解法清晰地模拟了比赛的配对和晋级过程,有效地解决了 “比赛配对问题”。