LeetCode 51. N-Queens

问题描述

这里写图片描述

问题分析

  • 大名鼎鼎的 N 皇后问题,要求n个皇后中任意两个元素都不处于同一行,同一列,同一对角线,返回所有的可能性放置结果。
  • 既然是返回所有的可能性,那么一定是用 dfs 去搜索所有的结果。以每一行为单位(这样保证同一行没有重复皇后),尝试在该行的每一列上放置皇后,若与该位置处于同一列或者同一对角线已有元素,那么剪枝。否则,继续对下一层进行 dfs。直至dfs到最后一层,收集结果。
    这里写图片描述
  • 那么如何判断同一列,同一对角线没有元素呢?

    • 对于同一列,可以用一个 colVisited[n]数组,colVisited[i] = true 表示第 i 列已有元素。
    • 对于对角线而言,需要考虑左右两个方向的对角线,每个方向的对角线都有2*n-1 条。
      对于右上到左下下对角线,处于同一对角线的元素,x,y坐标之和相等,所以,对于该方向对角线,可以用一个长度为 2*n - 1d1[k] = true 来表示 坐标和为 k的对角线已经有了元素。
      这里写图片描述
      对于 左上到右下方向的对角线,处于同一对角线的元素,x,y坐标之差相等,所以,对于该方向的对角线, 如果[x,y] 已有元素,那么 d2[i - j + n - 1] = true , 加 n- 1 是为了保证0索引开始。
      这里写图片描述
  • 该实现中还有个小技巧便是,用 pos.get(i) = j ,来表示第 i 行 第 j 列放置了皇后,便于最后生成为二维矩阵.

经验教训

  • 如何从一个问题抽象出来,看成一个dfs的问题,dfs如何进行,回溯如何使用,这是一个重点。

代码实现

class Solution {
    public List<List<String>> solveNQueens(int n) {
        if (n <= 0) {
            return new ArrayList<>();
        }
        List<List<String>> res = new ArrayList<>();
        //左对角线
        boolean[] d1 = new boolean[2 * n - 1];
        //右对角线
        boolean[] d2 = new boolean[2 * n - 1];
        //该列是否已有皇后
        boolean[] colVisited = new boolean[n];
        //从第0行开始,逐行放置皇后,列出所有可能性结果
        findQueens(n, 0, colVisited, d1, d2, new ArrayList<>(), res);
        return res;
    }

    //在第 row 行 及其之后行放置皇后,pos.get(i) = j ,是标志 第 i 行的皇后放在了第 j列
    public void findQueens(int n, int row, boolean[] colVisited, boolean[] d1, boolean[] d2, ArrayList<Integer> pos, List<List<String>> res) {
        //所有行都已经添加完毕
        if (row == n) {
            res.add(generateGrid(pos));
            return;
        }

        //将皇后放在第row行第j列
        for (int j = 0; j < n; j++) {
            //若当前列或者当前对角线已有皇后,则不能放置
            if (colVisited[j] || d1[row + j] || d2[row - j + n - 1]) {
                continue;
            }
            //第row行第j列符合规范
            //设置标志
            colVisited[j] = true;
            d1[row + j] = true;
            d2[row - j + n - 1] = true;
            pos.add(j);
            //dfs
            findQueens(n, row + 1, colVisited, d1, d2, pos, res);
            //利用回溯,恢复标志
            colVisited[j] = false;
            d1[row + j] = false;
            d2[row - j + n - 1] = false;
            //恢复pos
            pos.remove(pos.size() - 1);
        }
        return;
    }

    //根据 pos来填满整个矩阵: pos.get(i) = j ,是标志 第 i 行的皇后放在了第 j列
    public ArrayList<String> generateGrid(ArrayList<Integer> pos) {
        ArrayList<String> res = new ArrayList<>();
        int n = pos.size();
        for (int i = 0; i < n; i++) {
            int col = pos.get(i);
            StringBuilder sb = new StringBuilder();
            for (int k = 0; k < n; k++) {
                sb.append(k == col ? 'Q' : '.');
            }
            res.add(sb.toString());
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值