方法一:从国王出发
思路:思路不难,但枚举的方法有点秒
我们可以依次枚举八个方向,并从国王出发,其遇到的第一个皇后就可以攻击它。
记国王的位置为 ( k x , k y ) (k_x,k_y) (kx,ky),枚举的方向为 ( d x , d y ) (d_x,d_y) (dx,dy),那么我们不断地将 k x k_x kx 加上 d x d_x dx,将 k y k_y ky 加上 d y d_y dy,直到遇到皇后或者走出边界位置。为了记录皇后的位置,我们可以使用一个 8 × 8 8\times 8 8×8 的二维数组,也可以使用一个哈希表,这样就可以在 O ( 1 ) O(1) O(1) 的时间内判断某一个位置是否有皇后。
核心代码:枚举八个方向
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;
}
}
}
代码
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;
}
};
方法二:从皇后出发
思路
我们枚举每个皇后,判断它是否在国王的八个方向上。如果在,说明皇后可以攻击到国王。
记国王的位置为 ( k x , k y ) (k_x,k_y) (kx,ky),皇后的位置为 ( q x , q y ) (q_x,q_y) (qx,qy),那么皇后相对于国王的位置为 ( x , y ) = ( q x − k x , q y − k y ) (x,y)=(q_x-k_x,q_y-k_y) (x,y)=(qx−kx,qy−ky),显然当 x = 0 x=0 x=0 或 y = 0 y=0 y=0 或 ∣ x ∣ = ∣ y ∣ |x|=|y| ∣x∣=∣y∣ 时,皇后可以攻击到国王,方向为 ( s g n ( x ) , s g n ( y ) ) (sgn(x),sgn(y)) (sgn(x),sgn(y)),其中 s g n ( x ) sgn(x) sgn(x) 为符号函数,当 x > 0 x>0 x>0 时为 1 1 1, x < 0 x<0 x<0 时为 − 1 -1 −1, x = 0 x=0 x=0 时为 0 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; //哈希表:key-方向,value-距离最近的皇后及距离
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; //根据x、y的方向来确定key
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;
}
};