“英雄决斗的最大胜利次数”学习方法心得 | 豆包MarsCode AI刷题

225 阅读5分钟

英雄决斗的最大胜利次数 | 豆包MarsCode AI刷题

青训营笔记创作活动方向一:学习方法与心得| 豆包MarsCode AI刷题

“英雄决斗的最大胜利次数”题目解析与解题思路

问题描述

小U和小F进行一场由 nn 轮组成的英雄决斗。每一轮,小U和小F各派出一位英雄对决,英雄的能力值决定胜负,能力值高者获胜。小U的出场顺序是固定的,即能力值为1,2,...,n1, 2, ..., n,而小F可以自由调整他的英雄出场顺序以最大化获胜轮数。

输入输出

  • 输入:
    numbernumber:表示比赛总轮数 nn。
    heroesheroes:一个数组,表示小F每个英雄的能力值。
  • 输出:
    返回一个整数,表示小F可以获得的最大胜利轮数。

解题思路

要解决这个问题,我们需要寻找一种策略,尽可能让小F的英雄在每轮比赛中击败小U的英雄:

  1. 排序:
    小U的英雄能力值是固定的,从1到 nn,因此小F只需要对他的英雄能力值进行升序排列,这样便可以匹配出最优对抗策略。

  2. 贪心算法:
    使用双指针技术,对小U和小F的英雄进行逐一匹配:

    • 小F的英雄尝试击败小U当前最弱的英雄。如果成功,小F的胜利次数增加,同时两人的指针均右移。
    • 如果当前小F的英雄无法击败小U的英雄,则小F指针右移,尝试下一个更强的英雄。
  3. 复杂度分析:
    排序的时间复杂度为 O(nlog⁡n)O(n \log n),匹配过程为 O(n)O(n),整体复杂度为 O(nlog⁡n)O(n \log n)。


解题过程中的难点与弯路

遇到的问题

  1. 初始逻辑错误:
    在一开始,我尝试暴力枚举所有可能的出场顺序以求解。这种方式虽然可以找到最优解,但随着 nn 增加,时间复杂度呈指数级增长,显然无法满足大规模输入的性能要求。
  2. 排序误区:
    起初我认为将小F的英雄按降序排列能直接找到最优解,但在实际操作时发现,这种方法并未充分考虑小U的英雄顺序,会导致小F的部分强力英雄“浪费”在无意义的匹配上。
  3. 边界条件:
    当 heroesheroes 全部为相同值时,容易漏考虑小F无法获胜的情况。

豆包MarsCode的助力

  1. 代码逻辑诊断:
    在我初步实现暴力解法后,豆包MarsCode AI指出其在输入规模较大时性能极差,并建议使用更高效的贪心策略。这让我意识到算法设计的优劣对运行效率的极大影响。
  2. 边界测试:
    AI 自动生成了边界测试用例,如 heroes=[1,1,1,1,1]heroes = [1, 1, 1, 1, 1] 和 heroes=[10,9,8,7,6]heroes = [10, 9, 8, 7, 6]。通过这些测试,我发现自己的初始代码在特殊情况下输出错误。
  3. 性能优化建议:
    AI 提示我在逻辑上可通过双指针避免多余计算,同时直接排序小F的英雄,简化了匹配逻辑。

优化前后的代码对比

初始暴力解法(优化前)

def solution_bruteforce(number, heroes):
    from itertools import permutations

    u_heros = list(range(1, number + 1))
    max_wins = 0

    # 遍历所有小F英雄的排列组合
    for perm in permutations(heroes):
        wins = 0
        for i in range(number):
            if perm[i] > u_heros[i]:
                wins += 1
        max_wins = max(max_wins, wins)

    return max_wins

问题分析:

  • 时间复杂度高达 O(n!)O(n!),即使对于 n=10n = 10 也难以运行。
  • 对于边界情况,如 heroesheroes 全相同,算法仍会进行无意义的排列计算。

优化后代码(豆包MarsCode建议)

def solution(number, heroes):
    # 小U的英雄能力固定
    u_heros = list(range(1, number + 1))
    
    # 小F的英雄能力排序
    f_heros = sorted(heroes)
    win_turns = 0
    u_index = 0
    f_index = 0

    # 双指针匹配
    while u_index < number and f_index < number:
        if f_heros[f_index] > u_heros[u_index]:
            win_turns += 1
            u_index += 1
            f_index += 1
        else:
            f_index += 1

    return win_turns

改进效果:

  • 时间复杂度降至 O(nlog⁡n)O(n \log n),处理大规模数据时性能显著提升。
  • 逻辑清晰,避免了不必要的重复计算。
  • 考虑了边界情况,所有测试用例均通过。

使用豆包MarsCode的学习总结

学到的新知识点

  1. 贪心算法的应用:
    贪心算法通过每次选择局部最优解来尝试达到全局最优解,尤其适合本题这样的问题。
  2. 双指针技术:
    双指针常用于数组或链表的遍历操作,在处理类似“匹配问题”时非常高效。
  3. 性能分析的重要性:
    在解题时,不仅需要关注逻辑正确性,更要关注时间复杂度和代码的执行效率。

学习建议

  1. 主动思考:
    在查看AI优化建议前,先尝试自己分析代码的不足之处。
  2. 充分利用AI资源:
    在解题后可以让AI给出多种解题方法,并尝试自己理解并分析不同解题方法的优劣,可以提升自己的算法能力。