题目描述
在一个 8x8 的棋盘上,放置着若干「黑皇后」和一个「白国王」。
给定一个由整数坐标组成的数组 queens ,表示黑皇后的位置;以及一对坐标 king ,表示白国王的位置,返回所有可以攻击国王的皇后的坐标(任意顺序)。
示例
输入:queens = [[0,1],[1,0],[4,0],[0,4],[3,3],[2,4]], king = [0,0]
输出:[[0,1],[1,0],[3,3]]
解释:
[0,1] 的皇后可以攻击到国王,因为他们在同一行上。
[1,0] 的皇后可以攻击到国王,因为他们在同一列上。
[3,3] 的皇后可以攻击到国王,因为他们在同一条对角线上。
[0,4] 的皇后无法攻击到国王,因为她被位于 [0,1] 的皇后挡住了。
[4,0] 的皇后无法攻击到国王,因为她被位于 [1,0] 的皇后挡住了。
[2,4] 的皇后无法攻击到国王,因为她和国王不在同一行/列/对角线上。
解法:枚举
思路
对每个皇后进行遍历,判断是否在八个方向上。
如果在同一行上,横坐标相等;
queen[0] == king[0]
如果在同一列上,纵坐标相等;
queen[1] == king[1]
如果在同一对角线上,横坐标之差与纵坐标之差相等。
abs(king[0] - queen[0]) == abs(king[1] - queen[1])
因为同个方向上较远皇后的攻击会被最近皇后阻挡,因此对每个方向要取距离最近的皇后。为满足上述要求,定义一个以方向为key的哈希表,存储每个方向最近的皇后,以及她到国王的距离。
unordered_map<int, pair<vector<int>, int>> candidates;
//求出方向
int sx = sign(dx), sy = sign(dy);
//key代表方向的哈希映射
//为什么sx后面要乘上一个数?因为要放大哈希映射之间的距离,否则可能映射到同一个值
int key = sx*4 + sy;
int distance = abs(dx)+abs(dy);
//如果当前方向没有皇后直接放入,否则判断当前皇后的距离是否比哈希表里皇后更近
if(!candidates.count(key) || candidates[key].second > distance)
candidates[key] = {queens[i], distance};
完整代码
int sign(int x)
{
//x大于0返回1,否则判断x是否等于0,等于0时返回0,否则返回-1
return x>0?1:(x==0?0:-1);
}
vector<vector<int>> queensAttacktheKing(vector<vector<int>>& queens, vector<int>& king) {
int len = queens.size();
unordered_map<int, pair<vector<int>, int>> candidates;
int kx = king[0], ky = king[1];
for(int i=0; i<len; i++)
{
int qx = queens[i][0], qy = queens[i][1];
int dx = kx-qx, dy = ky - qy;
//同行 //同列 //同对角线
if(dx==0 || dy==0 || abs(dx)==abs(dy))
{
//求出方向
int sx = sign(dx), sy = sign(dy);
//key代表方向的哈希映射
//为什么sx后面要乘上一个数?因为要放大哈希映射之间的距离,否则可能映射到同一个值
int key = sx*4 + sy;
int distance = abs(dx)+abs(dy);
//如果当前方向没有皇后直接放入,对每个方向保留距离更近的皇后,较远皇后的攻击会被阻挡
//firsrt和second是pair的属性,first代表前面的vector即最近的queen,second代表后面的int也就是distance
if(!candidates.count(key) || candidates[key].second > distance)
candidates[key] = {queens[i], distance} ;
}
}
vector<vector<int>>ans;
for(auto [_, value]:candidates)
ans.push_back(value.first);
return ans;
}