【模拟】【数组】
1222. 可以攻击国王的皇后
在一个 8 × 8 8 \times 8 8×8 的棋盘上,有若干个「黑皇后」和一个「白国王」。现在有一个整数矩阵 queens
,表示黑皇后的位置;白国王的坐标为 king
。若白国王和某一个黑皇后在同一行、同一列或者在同一条对角线上,并且中间没有其他的黑皇后,则白国王可以攻击该黑皇后。返回可以被白国王攻击的黑皇后的位置。
本题解题方法有两种,一种是从白国王出发攻击,另一种是从黑皇后出发。这两种方法都要判断出里白国王最近的 “一圈” 黑皇后。
首先将 queens
中黑皇后的位置记录下来,然后枚举白国王可以走的八个方向,在每一个方向上遇到的第一个 queens
中的黑皇后,则该方向上可以攻击的黑皇后攻击完毕,换另一个方向查找可以攻击的黑皇后。
在具体实现中,使用一个集合 pos
将所有的黑皇后记录下来,对于网格中的位置 (x, y)
,我们可以使用 x * 8 + y
来唯一表示,集合 pos
记录的就是黑皇后的唯一表示位置。
实现代码
class Solution {
public:
vector<vector<int>> queensAttacktheKing(vector<vector<int>>& queens, vector<int>& king) {
auto sgn = [](int x) -> int {
return x > 0 ? 1 : (x == 0 ? 0 : -1);
};
unordered_map<int, pair<vector<int>, int>> candidates;
int kx = king[0], ky = king[1];
for (auto queen : queens) {
int qx = queen[0], qy = queen[1];
int dx = qx - kx, dy = qy - ky;
if (dx == 0 ||dy == 0 || abs(dx) == abs(dy)) {
int key = sgn(dx) * 10 + sgn(dy);
if (!candidates.count(key) || candidates[key].second > abs(dx) + abs(dy)) {
candidates[key] ={queen, abs(dx) + abs(dy)} ;
}
}
}
vector<vector<int>> res;
for (auto [_, candidate] : candidates) {
res.push_back(candidate.first);
}
return res;
}
};
复杂度分析
时间复杂度: O ( n + C ) O(n + C) O(n+C), n n n 为数组 queens
的长度,记录黑皇后位置的时间复杂度为 O ( n ) O(n) O(n), C = 8 C = 8 C=8 为,枚举八个方向上的黑皇后的时间复杂度为 O ( C ) O(C) O(C),总的时间复杂度为 O ( n + c ) O(n + c) O(n+c)。
空间复杂度: n n n,使用的额外空间是集合占用的空间。
从每个黑皇后出发,判断是否在白国王的八个方向上。我们枚举每个黑皇后的位置,与白国王的位置求 x
方向和 y
方向上的坐标差 dx
和 dy
:
dx = 0
,则黑皇后与白国王在同一列;dy = 0
,则黑皇后与白国王在同一行;abs(x) = abs(y)
,则黑皇后与白国王在对角线上。经过以上的判断,可以确定在白国王八个方向上的黑皇后,那如何判断是否离白国王最近呢?
我们通过与白国王之间的距离来判断,具体的用 abs(dx) + abs(dy)
来表示当前的黑皇后与白国王的距离。我们使用哈希表 candidates
来记录距离,键为方向的唯一表示,我们首先利用符号函数 s g n ( ) sgn() sgn() 来表示 黑皇后相对于白国王的方向。
s g n ( t ) = { 1 , t > 0 0 , t = 0 − 1 , t < 0 sgn \left( t \right) =\left\{ \begin{array}{l} 1,\ \ t>0\\ 0,\ \ t=0\\ -1,\ t<0\\ \end{array} \right. sgn(t)=⎩ ⎨ ⎧1, t>00, t=0−1, t<0
于是,键可以表示为 10 * sgn(x) + sgn(y)
。哈希表的值为 pair
,其中第一个数据为黑皇后的位置,第二个变量为当前的黑皇后与白国王的距离即 abs(dx) + dy
。于是,我们对 candidates
进行更新,设当前枚举的黑皇后的键为 key
:
!candidates.count(key)
,则 candidates
中没有当前的键,直接加入;candidates[key].second > abs(x) + abs(y)
,则找到离白国王最近的黑皇后,更新当前的值。最后,我们遍历 candidates
,记录离白国王最近的 “一圈” 黑皇后。
实现代码
class Solution {
public:
vector<vector<int>> queensAttacktheKing(vector<vector<int>>& queens, vector<int>& king) {
auto sgn = [](int x) -> int {
return x > 0 ? 1 : (x == 0 ? 0 : -1);
};
unordered_map<int, pair<vector<int>, int>> candidates;
int kx = king[0], ky = king[1];
for (auto queen : queens) {
int qx = queen[0], qy = queen[1];
int dx = qx - kx, dy = qy - ky;
if (dx == 0 ||dy == 0 || abs(dx) == abs(dy)) {
int key = sgn(dx) * 10 + sgn(dy);
if (!candidates.count(key) || candidates[key].second > abs(dx) + abs(dy)) {
candidates[key] ={queen, abs(dx) + abs(dy)} ;
}
}
}
vector<vector<int>> res;
for (auto [_, candidate] : candidates) {
res.push_back(candidate.first);
}
return res;
}
};
复杂度分析
时间复杂度: O ( n ) O(n) O(n), n n n 为数组 queens
的长度。
空间复杂度: O ( C ) O(C) O(C), C = 8 C = 8 C=8,也算是常数时间。
如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 。
如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。
最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 哦。