题目解析
本题的目标是帮助小 F 最大化在英雄对决比赛中的获胜次数。小 U 的英雄能力值已经固定,依次为 1, 2, 3, ..., n,而小 F 可以调整英雄出场顺序,以尽可能多地获得胜利。我们需要帮助小 F 找出一个最优的英雄出场顺序,使得他获得的胜利次数最大。
思路
-
小U的英雄能力固定:由于小U的英雄能力值是固定的,按顺序为
1, 2, ..., n,我们不需要对小U的英雄进行任何操作。这些能力值是递增的。 -
小F的英雄能力可调整:小F可以根据小U出场顺序调整自己的英雄出场顺序。为了最大化获胜次数,小F应该尽量用最小的英雄击败小U的英雄。这意味着小F应该尽量使用比当前小U英雄能力值大的最小英雄。
-
排序和匹配:通过对小F的英雄能力值进行排序,然后从小U的第一个英雄开始,依次为每个小U英雄选择一个能够击败它的最小小F英雄。这样可以保证每个小U英雄都尽量被小F击败,而不会浪费较强的小F英雄。
-
贪心策略:通过这种贪心的方式,小F可以确保每轮比赛都能以最小的代价赢得一场比赛,即用最小的英雄能力值击败小U的英雄。
代码详解
def solution(number, heroes):
# 小U的英雄能力值是固定的:1, 2, ..., n
u_heroes = list(range(1, number + 1))
# 小F的英雄能力值排序
heroes.sort()
# 小F的最大胜利次数
wins = 0
j = 0 # 小F的英雄指针
# 遍历小U的英雄
for u_hero in u_heroes:
# 找到一个能够击败小U英雄的最小英雄
while j < number and heroes[j] <= u_hero:
j += 1
if j < number: # 如果有能击败小U的英雄
wins += 1
j += 1 # 小F用掉了一个英雄
return wins
-
初始化小U的英雄能力值:
u_heroes变量表示小U的英雄能力值,按顺序排列为1, 2, ..., n。 -
排序小F的英雄能力值:
heroes.sort()对小F的英雄能力值进行升序排序,便于我们在后续的匹配过程中快速找到最小的可以击败小U英雄的能力值。 -
贪心匹配过程:
wins变量记录小F的获胜次数。- 使用
j变量作为小F英雄的指针,遍历小U的英雄时,尝试为每个小U英雄找到一个能够击败它的小F英雄。 - 对于每个小U英雄,
while j < number and heroes[j] <= u_hero:这段代码会跳过所有不可能击败小U英雄的英雄,直到找到一个比当前小U英雄能力值大的小F英雄。如果找到了,就增加wins,并将小F英雄的指针j向前移动,表示小F使用了该英雄。
-
返回最大胜利次数:最后返回小F的最大胜利次数
wins。
知识总结
-
贪心算法:在本题中,我们采用了贪心算法来最大化小F的胜利次数。贪心算法的核心思想是每次选择当前最优的解(即最小的英雄击败小U的英雄),并希望通过局部最优选择得到全局最优解。这种方法非常适合用于解决类似“匹配”和“分配”的问题。对于初学者来说,理解贪心算法的思想并能够在实际问题中应用非常重要。建议多做类似的贪心问题,理解如何通过贪心选择最优解,并验证贪心策略是否能保证全局最优。
-
排序的应用:排序是解决此类问题的常见技巧,通过对数组排序,可以简化很多匹配和选择过程。特别是在本题中,通过排序后,我们可以使用双指针法(一个指针遍历小U的英雄,另一个指针遍历小F的英雄)来快速找到合适的英雄进行匹配。
-
双指针技巧:本题中的
j变量充当了指针的角色,确保我们不会重复使用小F的英雄。双指针技巧常用于数组或列表的匹配问题,能够有效地减少不必要的计算。建议在学习过程中多做一些数组和列表相关的问题,练习如何通过排序、双指针等方法来优化解法。 -
时间复杂度分析:
- 排序的时间复杂度是 O(n log n),其中 n 是英雄的数量。
- 匹配的过程遍历了小U的所有英雄,所以时间复杂度为 O(n)。
- 因此,整体的时间复杂度是 O(n log n),这对于 n 最大为 10^5 的情况是非常高效的。
工具运用
豆包MarsCode AI 提供的刷题功能非常方便,可以帮助我们高效地进行算法训练。通过自动化的测试和解析,能够迅速理解问题的核心,并且在多次实践中积累经验。与 LeetCode、AcWing 等平台的题目结合使用,能够更好地拓宽自己的解题思路。