青训营X豆包MarsCode技术训练|豆包MarsCode AI 刷题

63 阅读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

解题思路 比赛的规则如下:

偶数队伍数:每两支队伍配对进行比赛,产生 n / 2 场比赛,剩下 n / 2 支队伍。 奇数队伍数:有一支队伍轮空,剩下的队伍按 n - 1 个队伍进行配对,即 (n - 1) / 2 场比赛,最终晋级队伍数为 (n - 1) / 2 + 1 支。 每轮比赛都会进行配对,而每次配对的次数就是队伍数减半的过程。我们可以通过模拟比赛的过程,逐步减少队伍数,计算每一轮的配对次数。

详细步骤 初始化:开始时队伍数为 n。 循环处理:每一轮: 如果队伍数为偶数:进行 n / 2 场比赛。 如果队伍数为奇数:进行 (n - 1) / 2 场比赛,并且有一支队伍轮空晋级。 更新队伍数:每轮晋级的队伍数为 (n + 1) / 2(即队伍数除以 2,并且如果是奇数还要加 1)。 终止条件:当队伍数为 1 时,比赛结束,不再进行任何配对。

代码实现:

image.png

解释 变量定义:

total_matches:记录总共进行的比赛次数。 n:当前队伍数。 循环过程:

每轮比赛中,如果 n 为偶数,则进行 n / 2 场比赛,并将 n 减半; 如果 n 为奇数,则进行 (n - 1) / 2 场比赛,并且有一支队伍轮空,剩下的队伍数为 (n - 1) / 2 + 1。 终止条件:当 n == 1 时,比赛结束,返回总配对次数。

复杂度分析 每次比赛都会减少一半的队伍数,因此时间复杂度为 O(log n),其中 n 是初始的队伍数。 测试用例 输入:n = 7

7 支队伍,进行 3 场比赛,剩 4 支队伍。 4 支队伍,进行 2 场比赛,剩 2 支队伍。 2 支队伍,进行 1 场比赛,剩 1 支队伍。 总配对次数:3 + 2 + 1 = 6 输入:n = 14

14 支队伍,进行 7 场比赛,剩 7 支队伍。 7 支队伍,进行 3 场比赛,剩 4 支队伍。 4 支队伍,进行 2 场比赛,剩 2 支队伍。 2 支队伍,进行 1 场比赛,剩 1 支队伍。 总配对次数:7 + 3 + 2 + 1 = 13 输入:n = 1

只有 1 支队伍,不需要进行任何比赛。 总配对次数:0

好的,下面是对这段代码的逐行解释:

cppCopy Code
#include <iostream>
#include <vector>
#include <string>
  • #include <iostream>:引入标准输入输出库,用于进行输入和输出操作,如 cout
  • #include <vector>:引入 STL 库中的 vector,虽然在本代码中并未实际使用,但通常用于存储动态数组。
  • #include <string>:引入 STL 库中的 string,该代码中也没有使用,但通常用于处理字符串。
cppCopy Code
using namespace std;
  • 使用标准命名空间 std,这样在代码中可以直接使用如 coutendlvector 等,而不需要加上 std:: 前缀。
cppCopy Code
int solution(int n) {
  • 定义了一个名为 solution 的函数,输入参数为 n(队伍数),返回类型为 int(返回总的配对次数)。
cppCopy Code
    int total_matches = 0; // 记录总共进行的配对次数
  • 初始化一个变量 total_matches,用来记录比赛的总配对次数。
cppCopy Code
    // 模拟比赛的过程,直到只剩一个队伍
    while (n > 1) {
  • 使用 while 循环,条件是 n > 1,即当队伍数大于 1 时继续比赛。如果 n 变为 1,表示比赛结束。
cppCopy Code
        // 如果队伍数为偶数,进行 n / 2 场比赛
        if (n % 2 == 0) {
  • 判断当前队伍数 n 是否为偶数。n % 2 == 0 判断 n 除以 2 的余数是否为 0,若是,说明 n 是偶数。
cppCopy Code
            total_matches += n / 2;
  • 如果 n 是偶数,则进行 n / 2 场比赛,每场比赛会消耗 2 支队伍。累加到 total_matches 中。
cppCopy Code
            n /= 2;  // 下一轮晋级的队伍数是 n / 2
  • 由于每场比赛会有一支队伍晋级,因此 n 变为原来的一半,即 n /= 2
cppCopy Code
        }
        // 如果队伍数为奇数,进行 (n - 1) / 2 场比赛,轮空一支队伍
        else {
  • 如果队伍数 n 为奇数,进入 else 分支。由于奇数不能完全配对,所以有一支队伍需要轮空。
cppCopy Code
            total_matches += (n - 1) / 2;
  • 由于有一支队伍轮空,剩下的 n - 1 支队伍可以配对进行比赛。因此,这一轮进行的比赛数是 (n - 1) / 2 场。累加到 total_matches 中。
cppCopy Code
            n = (n - 1) / 2 + 1;  // 下一轮晋级的队伍数是 (n - 1) / 2 + 1
  • 由于一支队伍轮空,所以下一轮晋级的队伍数是 (n - 1) / 2(进行比赛的队伍数)加上轮空的那支队伍,即 (n - 1) / 2 + 1
cppCopy Code
        }
    }
  • 结束 while 循环。直到队伍数 n 为 1 时,循环结束。
cppCopy Code
    return total_matches;
  • 返回 total_matches,即总共进行的配对次数。
cppCopy Code
}
  • 结束 solution 函数。
cppCopy Code
int main() {
  • 定义 main 函数,是程序的入口点。
cppCopy Code
    cout << (solution(7) == 6) << endl;  // 输出 6
  • 调用 solution(7),即当队伍数为 7 时,检查 solution 返回的结果是否等于 6(根据题意,应该是 6),输出结果。如果为真,输出 1;如果为假,输出 0
cppCopy Code
    cout << (solution(14) == 13) << endl; // 输出 13
  • 调用 solution(14),即当队伍数为 14 时,检查返回值是否为 13(按照逻辑推算结果为 13),输出结果。
cppCopy Code
    cout << (solution(1) == 0) << endl;  // 输出 0
  • 调用 solution(1),即当队伍数为 1 时,检查返回值是否为 0(因为不需要进行比赛,结果应该是 0),输出结果。
cppCopy Code
    return 0;
  • main 函数结束时,返回 0,表示程序成功运行。
cppCopy Code
}
  • 结束 main 函数。