51. N 皇后(难度:困难)

51. N 皇后(难度:困难)

题目链接:https://leetcode.cn/problems/n-queens/

题目描述

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

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

解法:回溯法

通过题目描述,皇后出现的位置,有四种情况是不允许的:

  • 同一行不能有两个皇后
  • 同一列不能有两个皇后
  • 从左上到右下一条斜线上不能有两个皇后
  • 从右上到左下一条斜线上不能有两个皇后

针对这四种不满足的情况,在不超时的情况下完成,只能是在O(1)的时间复杂度下才可以。

如何在O(1)时间复杂度完成呢?

我们通过观察下标,不难发现有一下规律:

  • 每一行是否有皇后,我们可以用一个数组来记录。
  • 每一列是否有皇后,我们也可以使用一个数组来记录。
  • 从左上到右下一条斜线上所有格子坐标(row,col),都会满足(row - col)相等,所以我们也可以使用一数组来记录。
  • 从右上到左下一条斜线上所有格子坐标(row,col),都会满足(row + col)相等,所以我们也可以使用一数组来记录。

代码:

class Solution {
    public List<List<String>> solveNQueens(int n) {
        List<List<String>> result = new ArrayList<>();
        int[] queues = new int[n];
        Arrays.fill(queues,-1);
        List<Integer> col = new ArrayList<>();
        List<Integer> diag1 = new ArrayList<>();
        List<Integer> diag2 = new ArrayList<>();

        build(result,n,0,queues,col,diag1,diag2);
        return result;

    }

    private void build(List<List<String>> result, int n, int row, int[] queues, List<Integer> col, List<Integer> diag1, List<Integer> diag2) {
        if(row == n) {
            List<String> re = buildResult(queues,n);
            result.add(re);
        } else {
            for(int i = 0;i<n;i++) {
                if(col.contains(i)) {
                    continue;
                }
                int d1 = row - i;
                if(diag1.contains(d1)) {
                    continue;
                }
                int d2 = row + i;
                if(diag2.contains(d2)) {
                    continue;
                }
                queues[row] = i;
                col.add(i);
                diag1.add(d1);
                diag2.add(d2);

                build(result,n,row+1,queues,col,diag1,diag2);

                queues[row] = -1;
                col.remove(row);
                diag1.remove(row);
                diag2.remove(row);
            }
        }
    }

    private List<String> buildResult(int[] queues, int n) {
        List<String> result = new ArrayList<>();

        for(int i = 0;i<queues.length;i++) {
            StringBuilder stringBuilder = new StringBuilder();
            for(int j = 0;j<n;j++) {
                if(j == queues[i]) {
                    stringBuilder.append("Q");
                } else {
                    stringBuilder.append(".");
                }
            }
            result.add(stringBuilder.toString());
        }
        return result;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值