力扣第五十二题-N皇后 II

870 阅读2分钟

这是我参与8月更文挑战的第19天,活动详情查看:8月更文挑战

前言

力扣第五十二题 N皇后 II 如下所示:

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

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

示例 1:

输入: n = 4
输出: 2
解释: 如上图所示,4 皇后问题存在两个不同的解法。

示例 2:

输入: n = 1
输出: 1

提示:

  • 1 <= n <= 9
  • 皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。

一、思路

N皇后 II力扣第五十一题-N 皇后 基本是一样。上一题求的是所有的解,这一题求得是解的数量。

题目中有三个非常重要的信息:

  • 皇后 彼此不能在同一行
  • 皇后 彼此不能在同一列
  • 皇后 彼此不能在同一斜线

大致的思路分为以下几个部分:

  1. 使用一个二维数组存储已选择的点在行列及斜线的占用情况
  2. 因为每一行都会有一个 皇后,所以当前递归中只遍历当前行的元素(剪枝)

变量说明:
boolean[][] positions; // 选择的元素
int[][] flags; // 占用情况(包含行、列、斜线)

与上一题不同的是,这一题只使用了一个 二维int数组 来存储三种占用情况。不管是 行占用列占用 还是 斜线占用,只要是 占用 就将 flags[i][j] + 1

使用一个二维数组存储占用情况,有两个好处:

  1. 占用的空间变少了,由之前的三个二维数组变为了只使用一个二维数组
  2. 代码更简洁,在 递归 时只需要判断 flags[i][j] 是否等于 0 即可

其他的思路均与上一题相同,故不再过多分析。

二、实现

实现代码

实现代码与思路中保持一致

tips:因为不需要返回结果,所以在每次找到结果后只需要将 ret ++ 即可

    boolean[][] positions;  // 选择元素记录
    int[][] flags;  // 占用情况(包含行、列、斜线)
    int len;
    int ret = 0;

    public int totalNQueens(int n) {
        flags = new int[n][n];
        positions = new boolean[n][n];
        len = n;
        dfs(0);
        return ret;
    }

    /**
     * 递归
     */
    public void dfs(int count) {
        if (count == len) {
            ++ret;
            return;
        }

        // 每一行都会有一个皇后,所以只需遍历n次
        for (int i=0; i<len; i++) {
            // 判断当前列是否可以放置皇后
            if (flags[count][i] == 0) {
                // 更新
                positions[count][i] = true;
                updateFlags(count, i, true);
                // 向下递归
                dfs(count+1);
                positions[count][i] = false;
                updateFlags(count, i, false);
            }
        }
    }

    public void updateFlags(int row, int col, boolean flag) {
        // 更新行
        for (int i=0; i< len; i++) {
            flags[row][i] = flag ? flags[row][i] + 1 : flags[row][i] -1;
        }
        // 更新列
        for (int i=0; i<len; i++) {
            flags[i][col] = flag ? flags[i][col] + 1 : flags[i][col] -1;
        }
        // 更新斜线
        int tRow = row; // 起始点(斜向下)
        int tCol = col;
        while (tRow>0 && tCol >0) {
            tRow--;
            tCol--;
        }
        // 更新斜向下
        while (tRow<len && tCol<len) {
            flags[tRow][tCol] = flag ? flags[tRow][tCol] + 1 : flags[tRow][tCol] -1;
            tRow++;
            tCol++;
        }
        tRow = row; // 起始点(斜向上)
        tCol = col;
        while (tRow>0 && tCol<len-1) {
            tRow--;
            tCol++;
        }
        // 更新斜向上
        while (tRow<len && tCol>-1) {
            flags[tRow][tCol] = flag ? flags[tRow][tCol] + 1 : flags[tRow][tCol] -1;
            tRow++;
            tCol--;
        }
    }

测试代码

测试代码如下所示:

    public static void main(String[] args) {
        new Number51().totalNQueens(8);
    }

结果

image.png

三、总结

感谢看到最后,非常荣幸能够帮助到你~♥