英雄决斗的最大胜利次数 | 豆包MarsCode AI刷题
青训营笔记创作活动方向一:学习方法与心得| 豆包MarsCode AI刷题
“英雄决斗的最大胜利次数”题目解析与解题思路
问题描述
小U和小F进行一场由 nn 轮组成的英雄决斗。每一轮,小U和小F各派出一位英雄对决,英雄的能力值决定胜负,能力值高者获胜。小U的出场顺序是固定的,即能力值为1,2,...,n1, 2, ..., n,而小F可以自由调整他的英雄出场顺序以最大化获胜轮数。
输入输出
- 输入:
numbernumber:表示比赛总轮数 nn。
heroesheroes:一个数组,表示小F每个英雄的能力值。 - 输出:
返回一个整数,表示小F可以获得的最大胜利轮数。
解题思路
要解决这个问题,我们需要寻找一种策略,尽可能让小F的英雄在每轮比赛中击败小U的英雄:
-
排序:
小U的英雄能力值是固定的,从1到 nn,因此小F只需要对他的英雄能力值进行升序排列,这样便可以匹配出最优对抗策略。 -
贪心算法:
使用双指针技术,对小U和小F的英雄进行逐一匹配:- 小F的英雄尝试击败小U当前最弱的英雄。如果成功,小F的胜利次数增加,同时两人的指针均右移。
- 如果当前小F的英雄无法击败小U的英雄,则小F指针右移,尝试下一个更强的英雄。
-
复杂度分析:
排序的时间复杂度为 O(nlogn)O(n \log n),匹配过程为 O(n)O(n),整体复杂度为 O(nlogn)O(n \log n)。
解题过程中的难点与弯路
遇到的问题
- 初始逻辑错误:
在一开始,我尝试暴力枚举所有可能的出场顺序以求解。这种方式虽然可以找到最优解,但随着 nn 增加,时间复杂度呈指数级增长,显然无法满足大规模输入的性能要求。 - 排序误区:
起初我认为将小F的英雄按降序排列能直接找到最优解,但在实际操作时发现,这种方法并未充分考虑小U的英雄顺序,会导致小F的部分强力英雄“浪费”在无意义的匹配上。 - 边界条件:
当 heroesheroes 全部为相同值时,容易漏考虑小F无法获胜的情况。
豆包MarsCode的助力
- 代码逻辑诊断:
在我初步实现暴力解法后,豆包MarsCode AI指出其在输入规模较大时性能极差,并建议使用更高效的贪心策略。这让我意识到算法设计的优劣对运行效率的极大影响。 - 边界测试:
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]。通过这些测试,我发现自己的初始代码在特殊情况下输出错误。 - 性能优化建议:
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(nlogn)O(n \log n),处理大规模数据时性能显著提升。
- 逻辑清晰,避免了不必要的重复计算。
- 考虑了边界情况,所有测试用例均通过。
使用豆包MarsCode的学习总结
学到的新知识点
- 贪心算法的应用:
贪心算法通过每次选择局部最优解来尝试达到全局最优解,尤其适合本题这样的问题。 - 双指针技术:
双指针常用于数组或链表的遍历操作,在处理类似“匹配问题”时非常高效。 - 性能分析的重要性:
在解题时,不仅需要关注逻辑正确性,更要关注时间复杂度和代码的执行效率。
学习建议
- 主动思考:
在查看AI优化建议前,先尝试自己分析代码的不足之处。 - 充分利用AI资源:
在解题后可以让AI给出多种解题方法,并尝试自己理解并分析不同解题方法的优劣,可以提升自己的算法能力。