2021-11-10 51. N 皇后(回溯法)

注:

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

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

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。

示例 1:
输入:n = 4
输出:[[".Q…","…Q",“Q…”,"…Q."],["…Q.",“Q…”,"…Q",".Q…"]]
解释:如上图所示,4 皇后问题存在两个不同的解法。
示例 2:
输入:n = 1
输出:[[“Q”]]

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

题解:
思路
都知道n皇后问题是回溯算法解决的经典问题,但是用回溯解决多了组合、切割、子集、排列问题之后,遇到这种二位矩阵还会有点不知所措。

首先来看一下皇后们的约束条件:

  1. 不能同行
  2. 不能同列
  3. 不能同斜线

确定完约束条件,来看看究竟要怎么去搜索皇后们的位置,其实搜索皇后的位置,可以抽象为一棵树。下面我用一个3 * 3 的棋牌,将搜索过程抽象为一颗树,如图:
在这里插入图片描述

从图中,可以看出,二维矩阵中矩阵的高就是这颗树的高度,矩阵的宽就是树形结构中每一个节点的宽度。

那么我们用皇后们的约束条件,来回溯搜索这颗树,只要搜索到了树的叶子节点,说明就找到了皇后们的合理位置了。

验证棋牌是否合法

  1. 不能同行
  2. 不能同列
  3. 不能同斜线 (45度和135度角)

如果令行作为递归的深度,则不需要在同行进行检查,因为在单层搜索的过程中,每一层递归,只会选for循环(也就是同一行)里的一个元素,所以不用去重了。

复杂度分析
时间复杂度:O(N!),其中 N 是皇后数量。

空间复杂度:O(N),其中 N 是皇后数量。空间复杂度主要取决于递归调用层数、记录每行放置的皇后的列下标的数组以及三个集合,递归调用层数不会超过 N,数组的长度为 N,每个集合的元素个数都不会超过 N。

class Solution {
public:
    vector<vector<string>> result;
    bool judge(vector<string>& path,int row,int col,int n){
        //检查列
        for(int i=0;i<row;i++){
            if(path[i][col]=='Q'){
                return false;
            }
        }
        //检查左上角
        for(int i=row,j=col;i>=0&&j>=0;i--,j--){
            if(path[i][j]=='Q'){
                return false;
            }
        }
        //检查右上角
        for(int i=row,j=col;i>=0&&j<n;i--,j++){
            if(path[i][j]=='Q'){
                return false;
            }
        }
        return true;
    }
    void backtracking(vector<string>& path,int row,int n){
        if(row==n){
            result.push_back(path);
            return ;
        }
        for(int col=0;col<n;col++){
            if(judge(path,row,col,n)==true){
                path[row][col]='Q';
                backtracking(path,row+1,n);
                path[row][col]='.';
            }
        }
    }
    vector<vector<string>> solveNQueens(int n) {
        vector<string> path(n,string(n,'.'));
        backtracking(path,0,n);
        return result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值