leetcode 51:N皇后

leetcode 51:N皇后

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

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

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

示例 1:

img

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

示例 2:

输入:n = 1
输出:[["Q"]]

提示:

  • 1 <= n <= 9

Related Topics

数组

回溯

回溯

分析:要保证皇后彼此之间不能攻击,必须不能放在同一行、同一列、同一个副对角线线(从右到左),主对角线(从左到右)。

  • 比如:实例1中从(0,0)---->(3,3)就是主对角线,(0,3)---->(3,0)就是副对角线。

我们可以每一行插入一个皇后,只要保证列、主对角线和、副对角线之间不攻击即可。所以需要三个标记数组,标记列、主对角线和副对角线。

  • 列直接根据列号标记即可。
  • 以实例n=4为例
  • 那么副对角线该如何标记?
    • 分析每一组下标的特点:第一组{(0,0)},第二组{(0,1),(1,0)},第三组{(0,2),(1,1),{2,0}}.
    • 相信大家已经看出了规律,i和j相加的和刚和等于组数。
  • 那么主对角线该如何标记?
    • 分析每一组下标的特点(n=4,总共7个对角线):我们以{(0,3)}为第7组,{(0,2),(1,3)}为第六组,{(0,1),(1,2),(2,3)}为第五组,以此类推
    • 我们可以发现j减去i的值为 -3,-2,-1,0,1,2,3。而数组下标的范围应该是0-6。我们只需要给每一个值加上3即可。
    • 当n等于4的时候,我们需要给j-i加3,那么当n=5时,我们需要给j-i加4,所以主对角线的下标值应该用j-i+n-1表示。

过程如下:

  • 先初始化矩阵。
  • 然后递归。
    • 当i等于n时,表明解出答案。
    • 当i不等于n时,因为每一列都有可能放入皇后,所以需要对第i行的列都遍历一遍。
      • 当列、副对角线、主对角线都符合,进行递归、回溯
      • 不符合,直接跳过
class Solution {
    private boolean[] columnFlag; //列标记
    private boolean[] lineLeftFlag; //副对角线  从右到左
    private boolean[] lineRightFlag; //主对象线  从左到右
    private List<List<String>> result = new ArrayList<>(); //结果
    private char[][] matrix;
    public List<List<String>> solveNQueens(int n) {

        //创建标记数组
        columnFlag = new boolean[n];
        lineLeftFlag = new boolean[(n-1)*2+1];
        lineRightFlag = new boolean[(n-1)*2+1];
        //初始化矩阵
        matrix = new char[n][n];
        for(int i = 0 ; i < n;i++){
            for(int j = 0 ; j < n;j++){
                matrix[i][j] = '.';
            }
        }
        //递归
        dfs(0,n);
        return result;
    }
    public void dfs(int i,int n){
        //找到N皇后结果
        if(i == n){
            List<String> list = new ArrayList<>();
            for(int j = 0 ; j < n;j++){
                list.add(new String(matrix[j]));
            }
            result.add(list);
            return;
        }
        //选取第i行第j列的位置
        for(int j = 0 ; j < n;j++){
            //判断每一列 副对角线、主对角线合法
            if(!columnFlag[j] && !lineLeftFlag[i+j] && !lineRightFlag[j-i+n-1]){
                //标记
                columnFlag[j] = true;
                lineLeftFlag[i+j] = true;
                lineRightFlag[j-i+n-1] = true;
                matrix[i][j] = 'Q';
                //递归
                dfs(i+1,n);
                matrix[i][j] = '.';
                //回溯
                columnFlag[j] = false;
                lineLeftFlag[i+j] = false;
                lineRightFlag[j-i+n-1] = false;
            }
        }
    }
}
解答成功:
			执行耗时:1 ms,击败了99.67%Java用户
			内存消耗:41.6 MB,击败了49.37%Java用户
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值