【力扣算法】52-N皇后II

题目

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

img

上图为 8 皇后问题的一种解法。

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

示例:

输入: 4
输出: 2
解释: 4 皇后问题存在如下两个不同的解法。
[
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-queens-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解

官方题解前半部分和上一题差不多,懒得复制了。主要是用位图那个方法值得看看:

方法 2:使用 bitmap 回溯

如果你是在面试中 - 使用方法 1。

下面的算法有着相同的时间复杂度 O ( N ! ) \mathcal{O}(N!) O(N!)。但是由于使用了位运算,可以运行得更快。

感谢这个算法的提出者 takaken.

为了便于理解该算法,下面的代码进行了逐步解释。

class Solution {
  public int backtrack(int row, int hills, int next_row, int dales, int count, int n) {
    /** 
     row: 当前放置皇后的行号
     hills: 主对角线占据情况 [1 = 被占据,0 = 未被占据]
     next_row: 下一行被占据的情况 [1 = 被占据,0 = 未被占据]
     dales: 次对角线占据情况 [1 = 被占据,0 = 未被占据]
     count: 所有可行解的个数
     */

    // 棋盘所有的列都可放置,
    // 即,按位表示为 n 个 '1'
    // bin(cols) = 0b1111 (n = 4), bin(cols) = 0b111 (n = 3)
    // [1 = 可放置]
    int columns = (1 << n) - 1;
    
    if (row == n)   // 如果已经放置了 n 个皇后
      count++;  // 累加可行解
    else {
      // 当前行可用的列
      // ! 表示 0 和 1 的含义对于变量 hills, next_row and dales的含义是相反的
      // [1 = 未被占据,0 = 被占据]
      int free_columns = columns & ~(hills | next_row | dales);
    
      // 找到可以放置下一个皇后的列
      while (free_columns != 0) {
        // free_columns 的第一个为 '1' 的位
        // 在该列我们放置当前皇后
        int curr_column = - free_columns & free_columns;
    
        // 放置皇后
        // 并且排除对应的列
        free_columns ^= curr_column;
    
        count = backtrack(row + 1,
                (hills | curr_column) << 1,
                next_row | curr_column,
                (dales | curr_column) >> 1,
                count, n);
      }
    }
    
    return count;
  }
  public int totalNQueens(int n) {
    return backtrack(0, 0, 0, 0, 0, n);
  }
}

复杂度分析

时间复杂度: O ( N ! ) \mathcal{O}(N!) O(N!).
空间复杂度: O ( N ) \mathcal{O}(N) O(N).

作者:LeetCode
链接:https://leetcode-cn.com/problems/two-sum/solution/nhuang-hou-ii-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

感想

把上一题代码改一改就好了

执行用时 :6 ms, 在所有Java提交中击败了43.76%的用户

内存消耗 :33.3 MB, 在所有Java提交中击败了54.69%的用户

class Solution {
    boolean[][] chessboard;
    int count = 0;
    public int totalNQueens(int n) {
        chessboard = new boolean[n][n];
        placeQueen(0);
        return count;
    }
    private boolean isLegal(int x, int y){
        int n=chessboard.length;
        for(int i=1;i<=x&&y>=i;i++){
            if(chessboard[x-i][y-i]) return false;
        }
        for(int i=1;i<=x&&n-y>i;i++){
            if(chessboard[x-i][y+i]) return false;
        }
        for(int i=0;i<x;i++){
            if(chessboard[i][y]) return false;
        }
        return true;
    }
    private void placeQueen(int x){
        int n = chessboard.length;
        for(int i=0;i<n;i++){
            if(isLegal(x,i)) {
                if(x<n-1){
                    chessboard[x][i]=true;
                    placeQueen(x+1);
                    chessboard[x][i]=false;  
                } 
                else {
                    count++;
                }
            }
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值