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

51 阅读3分钟

问题描述

小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. 赛制特点

根据题目描述:

  • 偶数队伍时,队伍数减半,配对次数为 n / 2
  • 奇数队伍时,会有一支队伍轮空,配对次数为 (n - 1) / 2,下一轮的队伍数为 (n - 1) / 2 + 1。 每轮比赛后队伍数会逐渐减少,因此可以通过模拟这一过程,计算累计的配对次数。

2. 逐轮模拟

比赛进行时,队伍数从 n 逐步减少:

  1. 如果 n 是偶数,每轮比赛会进行 n / 2 场,晋级 n / 2 支队伍。
  2. 如果 n 是奇数,先轮空一支队伍,剩余队伍进行 (n - 1) / 2 场比赛,晋级 (n - 1) / 2 + 1 支队伍。
  3. 重复上述过程,直到队伍数为 1,此时比赛结束。

3. 算法设计

使用一个循环模拟比赛过程:

  • 每轮根据队伍数是奇数还是偶数计算配对次数。
  • 累加每轮的配对次数,直到队伍数为 1。

4. 边界条件

  • 当 n = 1 时,没有比赛,配对次数为 0。
  • 当 n 很大时,通过逐轮减半的方式,算法能够高效完成计算。

代码实现

def solution(n: int) -> int:
    total_matches = 0
    
    while n > 1:
        if n % 2 == 0:
            # 如果队伍数为偶数
            total_matches += n // 2
            n //= 2
        else:
            # 如果队伍数为奇数
            total_matches += (n - 1) // 2
            n = (n - 1) // 2 + 1
    
    return total_matches

知识点总结

1. 奇偶数分类讨论

  • 偶数的特点:可以直接成对分组。
  • 奇数的特点:必须有一支队伍轮空,这种处理方式使得队伍数逐渐减少且问题有序。

2. 循环模拟的有效性

每轮比赛会将队伍数减少一半(或接近一半),循环的迭代次数为 log2(n)\log_2(n)。这一性质使得模拟过程的时间复杂度为 O(logn)O(\log n),可以高效处理非常大的 n

思考与优化

1. 时间复杂度分析

由于每轮队伍数减少一半,算法的时间复杂度为 O(logn)O(\log n)

2. 边界条件处理

  • n = 1:没有比赛,直接返回 0。
  • n 很大时:算法依然高效,可以处理百万级别的输入。

3. 递归实现

除了循环实现,还可以使用递归:

def solution(n: int) -> int:
    if n <= 1:
        return 0
    if n % 2 == 0:
        return n // 2 + solution(n // 2)
    else:
        return (n - 1) // 2 + solution((n - 1) // 2 + 1)

递归和循环实现的核心思想相同,均基于逐轮减少队伍数。