来源:力扣(LeetCode)
描述:
在一个 8x8 的棋盘上,放置着若干「黑皇后」和一个「白国王」。
给定一个由整数坐标组成的数组 queens
,表示黑皇后的位置;以及一对坐标 king
,表示白国王的位置,返回所有可以攻击国王的皇后的坐标(任意顺序)。
示例 1:
输入: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] 的皇后无法攻击到国王,因为她和国王不在同一行/列/对角线上。
示例 2:
输入:queens = [[0,0],[1,1],[2,2],[3,4],[3,5],[4,4],[4,5]], king = [3,3]
输出:[[2,2],[3,4],[4,4]]
示例 3:
输入:queens = [[5,6],[7,7],[2,1],[0,7],[1,6],[5,1],[3,7],[0,3],[4,0],[1,2],[6,3],[5,0],[0,4],[2,2],[1,1],[6,4],[5,4],[0,0],[2,6],[4,5],[5,2],[1,4],[7,5],[2,3],[0,5],[4,2],[1,0],[2,7],[0,1],[4,6],[6,1],[0,6],[4,3],[1,7]], king = [3,4]
输出:[[2,3],[1,4],[1,6],[3,7],[4,3],[5,4],[4,5]]
提示:
方法一:从国王出发
思路与算法
我们可以依次枚举八个方向,并从国王出发,其遇到的第一个皇后就可以攻击到它。
记国王的位置为 (kx, ky),枚举的方向为 (dx, dy),那么我们不断地将 kx 加上 dx,将 ky 加上 dy,直到遇到皇后或者走出边界位置。为了记录皇后的位置,我们可以使用一个 8 × 8 的二维数组,也可以使用一个哈希表,这样就可以在 O(1) 的时间内判断某一个位置是否有皇后。
代码:
class Solution {
public:
vector<vector<int>> queensAttacktheKing(vector<vector<int>>& queens, vector<int>& king) {
unordered_set<int> queen_pos;
for (const auto& queen: queens) {
int x = queen[0], y = queen[1];
queen_pos.insert(x * 8 + y);
}
vector<vector<int>> ans;
for (int dx = -1; dx <= 1; ++dx) {
for (int dy = -1; dy <= 1; ++dy) {
if (dx == 0 && dy == 0) {
continue;
}
int kx = king[0] + dx, ky = king[1] + dy;
while (kx >= 0 && kx < 8 && ky >= 0 && ky < 8) {
int pos = kx * 8 + ky;
if (queen_pos.count(pos)) {
ans.push_back({kx, ky});
break;
}
kx += dx;
ky += dy;
}
}
}
return ans;
}
};
时间 0ms 击败 100.00%使用 C++ 的用户
内存 10.96MB 击败 19.88%使用 C++ 的用户
复杂度分析
- 时间复杂度:O(n+C),其中 n 是数组 queens 的长度,C 是棋盘的大小,在本题中 C = 8 。我们需要 O(n) 的时间将所有皇后放入哈希表中,后续的枚举部分一共有 8 个方向,每两个对称的方向最多会遍历 C 个位置,因此一共最多遍历 4C = O© 个位置。
- 空间复杂度:O(n),即为哈希表需要使用的空间。
方法二:从皇后出发
思路与算法
我们枚举每个皇后,判断它是否在国王的八个方向上。如果在,说明皇后可以攻击到国王。
记国王的位置为 (kx, ky),皇后的位置为 (qx, qy),那么皇后相对于国王的位置为 (x, y) = (qx − kx, qy − ky),显然当 x = 0 或 y = 0 或 ∣x∣=∣y∣ 时,皇后可以攻击到国王,方向为 (sgn(x),sgn(y)),其中 sgn(x) 为符号函数,当 x > 0 时为 1,x < 0 时为 −1,x = 0 时为 0。
同一个方向的皇后可能有多个,我们需要选择距离国王最近的那一个,因此可以使用一个哈希映射,它的键表示某一个方向,值是一个二元组,分别表示当前距离最近的皇后以及对应的距离。当我们枚举到一个新的皇后时,如果它在国王的八个方向上,就与哈希映射中对应的值比较一下大小关系即可。
当枚举完所有皇后,我们就可以从哈希映射值的部分中得到答案。
代码:
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 (const auto& queen: queens) {
int qx = queen[0], qy = queen[1];
int x = qx - kx, y = qy - ky;
if (x == 0 || y == 0 || abs(x) == abs(y)) {
int dx = sgn(x), dy = sgn(y);
int key = dx * 10 + dy;
if (!candidates.count(key) || candidates[key].second > abs(x) + abs(y)) {
candidates[key] = {queen, abs(x) + abs(y)};
}
}
}
vector<vector<int>> ans;
for (const auto& [_, value]: candidates) {
ans.push_back(value.first);
}
return ans;
}
};
时间 0ms 击败 100.00%使用 C++ 的用户
内存 10.85MB 击败 31.25%使用 C++ 的用户
复杂度分析
- 时间复杂度:O(n),其中 n 是数组 queens 的长度。
- 空间复杂度:O(1)。
author:力扣官方题解