LeetCode 52 N皇后II 题解

LeetCode 52 N皇后II 题解

LeetCode 链接

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回 n 皇后问题 不同的解决方案的数量。

示例 1:
在这里插入图片描述

输入:n = 4
输出:2
解释:如上图所示,4 皇后问题存在两个不同的解法。
示例 2:
输入:n = 1
输出:1
提示:
1 <= n <= 9
皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。

官方题解

方法1

一行一行的放,一列一列的试探
在这里插入图片描述

利用三个集合保存列和两条对角线的元素存放情况
时间复杂度:O(N!),其中 N 是皇后数量。
空间复杂度:O(N),其中 N 是皇后数量。空间复杂度主要取决于递归调用层数以及三个集合,递归调用层数不会超过 N,每个集合的元素个数都不会超过 N。

class Solution {
    public int totalNQueens(int n) {
        if(n <= 0){
            return 0;
        }
        Set<Integer> columns = new HashSet<>(n);
        Set<Integer> diagonals1 = new HashSet<>(n);
        Set<Integer> diagonals2 = new HashSet<>(n);
        //从第0行开始向下试探
        return dfs(0, n, columns, diagonals1, diagonals2);
    }
    //递归回溯
    public int dfs(int row, int n, Set<Integer> columns, Set<Integer> diagonals1, Set<Integer> diagonals2){
        if(row == n){
            //到底了,说明这种方案可行
            return 1;
        }
        else{
            int count = 0;
            //一列一列的试探
            for(int col = 0; col < n; ++col){
                if(columns.contains(col)){
                    continue;
                }
                //左上右下对角线的row-col为常数
                int diagonal1 = row - col;
                if(diagonals1.contains(diagonal1)){
                    continue;
                }
                //右上左下对角线的row+col为常数
                int diagonal2 = row + col;
                if(diagonals2.contains(diagonal2)){
                    continue;
                }
                //当前列可以放置皇后
                columns.add(col);
                diagonals1.add(diagonal1);
                diagonals2.add(diagonal2);
                //递归计算所有可行解的数量
                count += dfs(row + 1, n, columns, diagonals1, diagonals2);
                //回溯
                columns.remove(col);
                diagonals1.remove(diagonal1);
                diagonals2.remove(diagonal2);
            }
            return count;
        }
    }
}

方法2

位运算牛逼!
需要注意的地方在于:皇后所在的整个一条对角线都不能放其他皇后了,所以对角线里❌和皇后所在位置都为1,然后一起向右或者向左移动一格来计算下一行不能放置的位置;其他内容看题解和注释
时间复杂度:O(N!),其中 N是皇后数量。
空间复杂度:O(N),其中 N 是皇后数量。由于使用位运算表示,因此存储皇后信息的空间复杂度是 O(1),空间复杂度主要取决于递归调用层数,递归调用层数不会超过 N。

class Solution {
    public int totalNQueens(int n) {
        if(n <= 0){
            return 0;
        }
        //从第0行开始向下试探,初始时没有放皇后,三个整数都是0;注意java int类型占32位
        return dfs(0, n, 0, 0, 0);
    }
    //递归回溯
    public int dfs(int row, int n, int columns, int diagonals1, int diagonals2){
        if(row == n){
            //到底了,说明这种方案可行
            return 1;
        }
        else{
            int count = 0;
            //计算可用的位置;2^n-1可以得到n个1,计算只用到n位,其他位置0
            int positions = ((1 << n) - 1) & (~(columns | diagonals1 | diagonals2));
            while(positions != 0){
                //只留下最后一个1:
                int position = positions & (-positions);
                //更新三个整数并递归统计解的个数
                count += dfs(row + 1, n, columns|position, (diagonals1|position)>>1, (diagonals2|position)<<1);
                //将最后一个1变成0:
                positions &= (positions - 1);
                //不用回溯,因为下一行的三个整数是传入的计算后的值,但是这三个整数本身没改变,还能继续用
            }
            return count;
    }
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值