1222. 可以攻击国王的皇后

文章目录

  • Tag
  • 题目来源
  • 题目解读
  • 解题思路
    • 方法一:从白国王出发
    • 方法二:从黑皇后出发
  • 写在最后

Tag

【模拟】【数组】


题目来源

1222. 可以攻击国王的皇后

1222. 可以攻击国王的皇后_第1张图片

题目解读

在一个 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 方向上的坐标差 dxdy

  • 如果 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=01, t<0

于是,键可以表示为 10 * sgn(x) + sgn(y)。哈希表的值为 pair, int>,其中第一个数据为黑皇后的位置,第二个变量为当前的黑皇后与白国王的距离即 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,也算是常数时间。


写在最后

如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 。

如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。

最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 哦。

你可能感兴趣的:(LeetCode每日一题,模拟,数组,C++,算法)