Leetcode 51.N皇后

220 阅读2分钟

Leetcode 51.N皇后

原题链接

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q''.' 分别代表了皇后和空位。

示例:

img

核心思路:

dfs深搜 关键在于三个约束条件如何记录:行row 列col 斜线dg与udg

  • 行row:枚举每一行即可
  • 列col:用数组vector<bool> col判断是否枚举到
  • 至于斜线dg和udg则是重点解决问题

leet51.png

如图,两条黑(主斜线dg)格子坐标相减为定值即x-y=c 两条红(副斜线)格子坐标相加为定值即x+y=c

在主斜线上我们得出结论:在主斜线dg上,如果坐标满足x-y=c(定值)上,则这些所有坐标在同一斜线上。如图 x-y = 0 的坐标在同一斜线上,x-y = -1的坐标也在同一斜线上(仍是主斜线 只是平行)

同理:在两条红(副斜线udg)上,坐标相加为定值即x+y=c也在同一斜线上。

代码块

class Solution {  
public:  
    vector<vector<string>> solveNQueens(int n) {  
        vector<vector<string>> result;  
        vector<bool> dg(2 * n); // 对角线数组的大小应该是2n  
        vector<bool> udg(2 * n); // 反对角线数组的大小也应该是2n  
        vector<bool> col(n); // 列数组的大小是n  
        vector<string> board(n, string(n, '.')); // 初始化棋盘  
  
        dfs(0, n, result, dg, udg, board, col);  
  
        return result;  
    }  
  
private:  
    void dfs(int u, int n, vector<vector<string>>& result, vector<bool>& dg, vector<bool>& udg, vector<string>& board, vector<bool>& col) {  
        if (u == n) {  
            result.push_back(board); // 将完整棋盘添加到结果中  
            return;  
        }  
  
        for (int y = 0; y < n; y++) {  
            int x = u; // 这里x是固定的,因为我们正在放置第u行的皇后  
            int dx = y - x + n; // 转换为非负索引  
            int ud = x + y; // 副对角线索引  
  
            if (!col[y] && !dg[dx] && !udg[ud]) {  
                col[y] = dg[dx] = udg[ud] = true;  
                board[x][y] = 'Q';  
                dfs(u + 1, n, result, dg, udg, board, col);  
                board[x][y] = '.';  //恢复现场
                col[y] = dg[dx] = udg[ud] = false;  
            }  
        }  
    }  
};

细节补充

  • 因为x-y=c为负值,故我们给x-y加上一个偏移量n使得x-y>0(数组索引没有负数),当然,偏移量可任选,只要满足x-y>0即可。

  • 至于dg和udg数组开2n空间是因为对角线有2n-1条。

  • if (!col[y] && !dg[dx] && !udg[ud]) 不同列 不同主对角 不同副对角。

  • 至于函数参数太多,应该可以采用开全局变量优化,有能力可以试试。