多角色游戏中的弱角色判定 —— 解题思路与代码详解
题目描述
在一款多角色的游戏中,每个角色有两个主要属性:攻击(attack)和防御(defense)。给你一个二维整数数组 properties,其中 properties[i] = [attack_i, defense_i] 表示第 i 个角色的属性。
定义“弱角色”如下:
如果存在另一个角色 j,使得 attack_j > attack_i 且 defense_j > defense_i,则角色 i 被认为是弱角色。
请你统计并返回弱角色的数量。
示例
- 示例 1:
输入: properties = [[5,5],[6,3],[3,6]]
输出: 0
解释: 没有角色的攻击和防御同时被另一角色严格超过。
- 示例 2:
输入: properties = [[2,2],[3,3]]
输出: 1
解释: 第一个角色被第二个角色的攻击和防御都超过,是弱角色。
- 示例 3:
输入: properties = [[1,5],[10,4],[4,3]]
输出: 1
解释: 第三个角色被第二个角色的攻击和防御都超过,是弱角色。
解题分析
这道题的核心难点在于如何快速判断对于某个角色 i,是否存在角色 j,满足:
attack_j > attack_idefense_j > defense_i
如果直接用两层循环比较,复杂度为 O(n²),当 n 非常大(题目限制最多 10^5)时,会超时。
因此需要借助排序和贪心思想优化。
解题思路
- 排序:
将角色按照攻击值 升序 排列。如果攻击值相同,则按照防御值 降序 排列。- 为什么这样排序?
同攻击值的角色中,防御高的排在前面,这样在后续判断时能避免误判。
因为“弱角色”要求攻击和防御都严格小于另一个角色,攻击相同的角色之间不存在严格“大于”的关系。
- 为什么这样排序?
- 逆序遍历并维护最大防御值:
从后向前遍历排序后的数组,维护一个变量max_defense,表示当前遍历过的角色中最大的防御值。- 如果当前角色的防御小于
max_defense,说明在它攻击更大的角色中,有一个角色的防御更大,当前角色就是弱角色。 - 否则,更新
max_defense。
- 如果当前角色的防御小于
代码实现
from typing import List
class Solution:
def numberOfWeakCharacters(self, properties: List[List[int]]) -> int:
# 按攻击升序,防御降序排序
properties.sort(key=lambda x: (x[0], -x[1]))
max_defense = 0
weak_count = 0
# 反向遍历,保证攻击值更大
for attack, defense in reversed(properties):
if defense < max_defense:
weak_count += 1 # 当前角色是弱角色
else:
max_defense = defense # 更新最大防御值
return weak_count
复杂度分析
- 时间复杂度:排序是 O(n log n),遍历一次是 O(n),整体是 O(n log n)。
- 空间复杂度:排序通常需要 O(log n) 的递归栈空间,算法中额外使用常数空间 O(1)。
代码讲解
properties.sort(key=lambda x: (x[0], -x[1]))
按攻击升序排序,如果攻击值相同,则防御值降序排序。for attack, defense in reversed(properties):
反向遍历,保证先看到攻击更大的角色。if defense < max_defense:
当前防御小于已遇到的最大防御,说明存在攻击更大且防御更大的角色,当前角色为弱角色。else: max_defense = defense
当前防御比最大防御还大,更新最大防御。
示例说明
以示例 [[2,2],[3,3]] 为例:
- 排序后是
[[2,2],[3,3]],因为本身就满足排序条件。 - 逆序遍历:
- 先看
[3,3],max_defense = 0,更新max_defense = 3。 - 再看
[2,2],2 < max_defense(3),弱角色数 +1。
- 先看
输出为 1,正确。
总结与思考
- 这道题考查了二维排序与贪心的结合应用。
- 关键在于排序策略,防止攻击值相同的角色造成误判。
- 逆序遍历维护最大防御值,能够在一次遍历中判断角色是否弱。
- 这类「二维条件筛选」的问题,类似于“skyline问题”或“包裹问题”,可以借鉴排序+扫描的思路。
381

被折叠的 条评论
为什么被折叠?



