leetcode51.N皇后(困难)-回溯法

思路

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

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

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

确定完约束条件,来看看究竟要怎么去搜索皇后们的位置,其实搜索皇后的位置,可以抽象为一棵树。

下面我用一个 3 * 3 的棋盘,将搜索过程抽象为一棵树,如图:

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

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

然后套用递归三部曲解决。

  • 递归函数参数
  • 递归终止条件
  • 单层搜索的逻辑

这里还要外加一个 :验证棋盘是否合法

按照如下标准去重:

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

java版本代码:

java 复制代码
class Solution {
    List<List<String>> res = new ArrayList<>(); //全局变量res集合,用于存储解决方案的列表

    // 解决N皇后问题的方法,返回解决方案的集合
    public List<List<String>> solveNQueens(int n) {
        char[][] chessboard = new char[n][n]; // 创建一个N*N的字符棋盘
        for (char[] c : chessboard) {
            Arrays.fill(c, '.'); // 初始化棋盘,填充为'.'
        }
        backTrack(n, 0, chessboard); // 调用回溯方法,开始搜索解决方案
        return res; // 返回所有解决方案的集合
    }

    // 回溯方法,用于搜索解决N皇后问题的解决方案
    // n 为输入的棋盘大小
    // row 是当前递归到棋盘的第几行了
    public void backTrack(int n, int row, char[][] chessboard) {
        if (row == n) { // 终止条件:如果已经填满了所有行,即找到了一种解决方案
            res.add(Array2List(chessboard)); // 将当前棋盘状态添加到解决方案的集合中(list集合里的元素还是个集合list,见示例)
            return;
        }

        for (int col = 0; col < n; ++col) { // 遍历当前行的所有列
            if (isValid(row, col, n, chessboard)) { // 如果当前位置可以放置皇后
                chessboard[row][col] = 'Q'; // 放置皇后
                backTrack(n, row + 1, chessboard); // 递归搜索下一行的解决方案
                chessboard[row][col] = '.'; // 回溯,撤销当前位置的皇后(把Q替换成 .即可)
            }
        }
    }

    // 将二维字符数组转换为字符串集合
    public List Array2List(char[][] chessboard) {
        List<String> list = new ArrayList<>(); // 创建一个空集合

        for (char[] c : chessboard) { // 遍历棋盘的每一行 字符数组:char[] c,eg:{"Q",".",".",".",} 、
            list.add(String.copyValueOf(c)); // 将当前行的字符数组char[] c 转换为字符串并添加到集合list中
        }
        return list; // 返回转换后的集合 eg:[".Q..","...Q","Q...","..Q."]
    }

    // 检查当前位置是否可以放置皇后isValid()方法  :从上往下去找的,所以对角线只找了左上和右上
    public boolean isValid(int row, int col, int n, char[][] chessboard) {
        // 检查同一列是否已经放置了皇后
        for (int i = 0; i < row; ++i) { // 遍历当前列之前的所有行
            if (chessboard[i][col] == 'Q') { // 如果当前位置上方有皇后
                return false; // 返回false,表示当前位置不能放置皇后
            }
        }

        // 检查45度对角线上是否已经放置了皇后
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { // 向左上方遍历
            if (chessboard[i][j] == 'Q') { // 如果当前位置左上方有皇后
                return false; // 返回false,表示当前位置不能放置皇后
            }
        }

        // 检查135度对角线上是否已经放置了皇后
        for (int i = row - 1, j = col + 1; i >= 0 && j <= n - 1; i--, j++) { // 向右上方遍历
            if (chessboard[i][j] == 'Q') { // 如果当前位置右上方有皇后
                return false; // 返回false,表示当前位置不能放置皇后
            }
        }
        return true; // 如果以上条件都不满足,表示当前位置可以放置皇后,返回true
    }
}
相关推荐
雪度娃娃几秒前
转向现代C++——优先选用删除函数而非private未定义函数
java·jvm·c++
Kurisu5752 分钟前
深度拆解:从 Linux 内核 Namespace 与 Cgroups 洞察容器技术的底层本质
java·linux·运维
罗超驿2 分钟前
11.LeetCode 1004. 最大连续1的个数 III | 滑动窗口解法详解(Java)
java·算法·leetcode
努力发光的程序员4 分钟前
面试官与程序员谢飞机的3轮Java大厂面试问答实录:涵盖Spring Boot、微服务与数据库技术
java·jvm·spring boot·redis·面试·hibernate·microservices
橙淮5 分钟前
并发编程(四)
java·jvm
我叫张小白。6 分钟前
Redis的缓存雪崩、击穿、穿透和解决方案
数据结构·redis·fastapi·缓存穿透·缓存击穿·雪崩·热点key问题
QiLinkOS7 分钟前
发明人与专利价值共生逻辑
c语言·数据结构·c++·人工智能·单片机·嵌入式硬件·算法
z落落10 分钟前
C# Stack栈 / Queue队列+所有集合 终极一页汇总(全覆盖、零遗漏)
java·开发语言·c#
计算机安禾18 分钟前
【算法分析与设计】第21篇:回溯法的状态空间树与剪枝函数设计
大数据·人工智能·算法·机器学习·数据挖掘·剪枝
磊 子19 分钟前
STL之set以及set和map区别
开发语言·c++·算法