52. N 皇后 II

题目:

思路:

【1】皇后的走法是:可以横直斜走,格数不限。因此要求皇后彼此之间不能相互攻击,等价于要求任何两个皇后都不能在同一行、同一列以及同一条斜线上。

【2】基于集合的回溯(模拟的方式)

【3】基于位运算的回溯

代码展示:

【2】基于集合的回溯(模拟的方式)

//时间3 ms 击败 37.25%
//内存39.1 MB 击败 27.81%
//时间复杂度:O(N!),其中 N 是皇后数量。
//空间复杂度:O(N),其中 N 是皇后数量。
//空间复杂度主要取决于递归调用层数以及三个集合,递归调用层数不会超过 N,每个集合的元素个数都不会超过 N。
class Solution {
    public int totalNQueens(int n) {
        Set<Integer> columns = new HashSet<Integer>();
        Set<Integer> diagonals1 = new HashSet<Integer>();
        Set<Integer> diagonals2 = new HashSet<Integer>();
        return backtrack(n, 0, columns, diagonals1, diagonals2);
    }

    /**
     *
     * @param n 表示在 n*n的棋盘上需要放N个皇后
     * @param row
     * 记录每一列以及两个方向的每条斜线上是否有皇后
     * @param columns
     * @param diagonals1
     * @param diagonals2
     * @return
     */
    public int backtrack(int n, int row, Set<Integer> columns, Set<Integer> diagonals1, Set<Integer> diagonals2) {
        // 如果能达到最低行就返回一次成功的排列
        if (row == n) {
            return 1;
        } else {
            int count = 0;
            // 看这一行的皇后可以放在哪个列
            for (int i = 0; i < n; i++) {
                // 如果列出现重复,那么就跳过
                if (columns.contains(i)) {
                    continue;
                }
                // 斜线为从左上到右下方向,同一条斜线上的每个位置满足行下标与列下标之差相等
                int diagonal1 = row - i;
                if (diagonals1.contains(diagonal1)) {
                    continue;
                }
                // 斜线为从右上到左下方向,同一条斜线上的每个位置满足行下标与列下标之和相等
                int diagonal2 = row + i;
                if (diagonals2.contains(diagonal2)) {
                    continue;
                }
                // 添加标记
                columns.add(i);
                diagonals1.add(diagonal1);
                diagonals2.add(diagonal2);
                // 递归下一行看看皇后放哪
                count += backtrack(n, row + 1, columns, diagonals1, diagonals2);
                // 删除标记对集合进行恢复
                columns.remove(i);
                diagonals1.remove(diagonal1);
                diagonals2.remove(diagonal2);
            }
            return count;
        }
    }
}

【3】基于位运算的回溯

//这个本质上是利用数值的进制位来替代 集合达到优化的效果
//时间0 ms 击败 100%
//内存38.1 MB 击败 74.40%
//时间复杂度:O(N!),其中 N 是皇后数量。
//空间复杂度:O(N),其中 N 是皇后数量。
//由于使用位运算表示,因此存储皇后信息的空间复杂度是 O(1),
//空间复杂度主要取决于递归调用层数,递归调用层数不会超过 N。
class Solution {
    public int totalNQueens(int n) {
        return solve(n, 0, 0, 0, 0);
    }

    public int solve(int n, int row, int columns, int diagonals1, int diagonals2) {
        if (row == n) {
            return 1;
        } else {
            int count = 0;
            int availablePositions = ((1 << n) - 1) & (~(columns | diagonals1 | diagonals2));
            while (availablePositions != 0) {
                int position = availablePositions & (-availablePositions);
                availablePositions = availablePositions & (availablePositions - 1);
                count += solve(n, row + 1, columns | position, (diagonals1 | position) << 1, (diagonals2 | position) >> 1);
            }
            return count;
        }
    }
}

 

posted @ 2023-07-20 18:22  忧愁的chafry  阅读(5)  评论(0编辑  收藏  举报