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

5 阅读5分钟

问题描述

小R正在组织一个比赛,比赛中有 n 支队伍参赛。比赛遵循以下独特的赛制:

  • 如果当前队伍数为 偶数,那么每支队伍都会与另一支队伍配对。总共进行 n / 2 场比赛,且产生 n / 2 支队伍进入下一轮。
  • 如果当前队伍数为 奇数,那么将会随机轮空并晋级一支队伍,其余的队伍配对。总共进行 (n - 1) / 2 场比赛,且产生 (n - 1) / 2 + 1 支队伍进入下一轮。

小R想知道在比赛中进行的配对次数,直到决出唯一的获胜队伍为止。

测试样例

样例1:

输入:n = 7
输出:6

样例2:

输入:n = 14
输出:13

样例3:

输入:n = 1
输出:0

思路分析

一、明确问题的递归性质

我们要计算比赛进行到决出唯一获胜队伍时的配对次数。每一轮比赛后队伍数量会发生变化,而这个变化后的情况又可以看作是一个新的、规模更小的同类型问题,这符合递归的特点,即问题可以分解为相似的子问题。

二、确定递归的终止条件

当只剩下一支队伍时,比赛结束,也就不再有配对比赛的情况发生了。所以递归的终止条件就是队伍数量等于 1 时,此时返回的配对次数应该是 0,因为已经决出冠军,不再需要进行新的配对了。

三、分析每一轮比赛的情况并构建递归关系

  1. 队伍数量为偶数时

    • 如果当前有n支队伍且n为偶数,那么这一轮会进行n/2场比赛(也就是n/2次配对),然后下一轮就会有n/2支队伍继续比赛。
    • 所以当n为偶数时,总的配对次数应该是这一轮的配对次数(n/2)加上下一轮比赛(以n/2支队伍进行比赛)所需要的配对次数。这里下一轮比赛所需的配对次数就可以通过递归调用函数来计算,因为它又是一个规模更小的同样问题,只是队伍数量变成了n/2。
  2. 队伍数量为奇数时

    • 如果当前有n支队伍且n为奇数,那么这一轮会进行(n-1)/2场比赛(也就是(n-1)/2次配对),然后下一轮就会有(n-1)/2+1支队伍继续比赛。
    • 所以当n为奇数时,总的配对次数应该是这一轮的配对次数((n-1)/2)加上下一轮比赛(以(n-1)/2+1支队伍进行比赛)所需要的配对次数。同样,下一轮比赛所需的配对次数可以通过递归调用函数来计算,此时队伍数量变成了(n-1)/2+1。

代码

int solution(int n) {
    // write code here
    int i=0;
    if(n==1){
        return i;
    }
    else if(n%2==0){
        i=n/2;
        return i+solution(i);
    }
    else{
        i=(n-1)/2;
        return i+solution(i+1);
    }
}

int main() {
    printf("%d\n", solution(7) == 6);
    printf("%d\n", solution(14) == 13);
    printf("%d\n", solution(1) == 0);

    return 0;
}

代码解析

  • 变量声明

    • 在函数开头声明了一个整型变量 i,并初始化为 0,这个变量用于记录当前轮次的配对次数。
  • 递归终止条件(n == 1

    • 当传入的队伍数量 n 等于 1 时,意味着已经决出了唯一的获胜队伍,此时不需要再进行任何配对比赛了,所以直接返回 i(其值为 0)。
  • 队伍数量为偶数情况(n % 2 == 0

    • 当 n 是偶数时,根据赛制,每支队伍都会与另一支队伍配对,总共会进行 n / 2 场比赛,也就是 n / 2 次配对。所以先将 i 赋值为 n / 2
    • 然后,因为这一轮比赛结束后,会有 n / 2 支队伍进入下一轮继续比赛,而下一轮比赛所需要的配对次数同样可以通过调用 solution 函数来计算(这就是递归调用),所以最终返回当前轮次的配对次数 i 加上下一轮比赛(队伍数量变为 n / 2)所需的配对次数 solution(i)
  • 队伍数量为奇数情况(n % 2!= 0

    • 当 n 是奇数时,根据赛制,将会随机轮空并晋级一支队伍,其余的队伍配对,总共会进行 (n - 1) / 2 场比赛,即 (n - 1) / 2 次配对。所以先将 i 赋值为 (n - 1) / 2
    • 接着,这一轮比赛结束后,会有 (n - 1) / 2 + 1 支队伍进入下一轮继续比赛,同样需要调用 solution 函数来计算下一轮比赛(队伍数量变为 (n - 1) / 2 + 1)所需的配对次数(递归调用),最后返回当前轮次的配对次数 i 加上下一轮比赛所需的配对次数 solution(i + 1)

知识点总结

在解决这个问题中我们用到了递归算法。递归就是在函数的定义中使用函数自身的方法。一个函数直接或间接地调用自身来解决问题,将复杂的大问题逐步分解为与原问题相似但规模更小的子问题,直到子问题简单到可以直接求解(即达到递归终止条件)。递归算法中的关键要素是递归的终止条件和递归关系,这两点弄明白了就可以用递归算法解决基本问题了。