题目链接
https://leetcode-cn.com/problems/the-number-of-weak-characters-in-the-game/
题目描述
你正在参加一个多角色游戏,每个角色都有两个主要属性:攻击 和 防御 。给你一个二维整数数组 properties
,其中 properties[i] = [attack_i, defense_i]
表示游戏中第 i
个角色的属性。
如果存在一个其他角色的攻击和防御等级 都严格高于 该角色的攻击和防御等级,则认为该角色为 弱角色 。更正式地,如果认为角色 i
弱于 存在的另一个角色 j
,那么 attack_j > attack_i
且 defense_j > defense_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
解释:第三个角色是弱角色,因为第二个角色的攻击和防御严格大于该角色。
提示
2 <= properties.length <= 105
properties[i].length == 2
1 <= attack_i, defense_i <= 105
思路
-
这个题我并没有想到什么好的办法。数据规模1e5,所以不能使用 O ( n 2 ) O(n^2) O(n2)的暴力方法;
-
其实,这个题的关键在于排序,首先按照一个属性从大到小排序,然后依次遍历每个角色。对每个角色来说,比它强的角色只可能出现在这个角色前面,只有它的前面有角色另外一个属性严格高于它时,它才可能是弱角色。因此,只要在遍历的过程中记录另一个属性的最大值即可;
-
还有一个问题是,会有角色攻击力相同或者防御力相同。比如首先按照攻击力从大到小排序,并在遍历过程中计算到当前角色之前防御力的最大值
max1
,那么即便max1
大于当前角色的防御力,但是防御力是max1的角色攻击力可能和当前角色相同,因此不能保证当前角色一定是弱角色。为了解决这个问题,可以对排序进行改进:对于攻击力不同的角色,按攻击力从大到小排序;对于攻击力相同的角色,按防御力从小到大排序。这样,当我们在遍历的时候,如果max1
大于当前角色防御力,那么防御力取到max1
的角色的攻击力一定也大于当前角色,也就可以确定当前角色是弱角色。
代码
#include<bits/stdc++.h>
using namespace std;
bool cmp(vector<int> & a, vector<int> &b)
{
return a[0] == b[0]? (a[1] < b[1]) : (a[0] > b[0]);
}
class Solution {
public:
int numberOfWeakCharacters(vector<vector<int>>& properties) {
sort(properties.begin(), properties.end(), cmp);
int max1 = -1;
int cnt = 0;
for(auto p : properties)
{
if(p[1] >= max1) max1 = p[1];
else cnt++;
}
return cnt;
}
};
思路2
这个题也可以反过来排序,使用单调栈的思路。按照攻击力作为第一关键字升序,防御力作为第二关键字降序。这个问题可以看作为每个角色寻找序列后面第一个防御力大于它的角色。
代码如下:
bool cmp(vector<int> &a, vector<int> &b)
{
return (a[0] == b[0])? (a[1] > b[1]) : (a[0] < b[0]);
}
class Solution {
public:
int s[1000000]; // 数组模拟栈
int top; // 栈顶位置
int numberOfWeakCharacters(vector<vector<int>>& properties) {
sort(properties.begin(), properties.end(), cmp);
top = -1;
int cnt = 0;
for(auto p : properties)
{
while(top != -1 && s[top] < p[1])
{
cnt++;
top--;
}
s[++top] = p[1];
}
return cnt;
}
};