《代码随想录》Ⅶ 回溯算法-棋盘 51. N 皇后

《代码随想录》Ⅶ 回溯算法-棋盘 51. N 皇后

努力学习!

题目:力扣链接

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

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

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

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

一、思想

这道题的核心思想是使用回溯算法。回溯算法是一种通过递归尝试所有可能的解,并在发现当前解不符合条件时进行回退的算法。在N皇后问题中,我们需要在每一行放置一个皇后,并确保每一列和每一条斜线上都没有其他皇后。通过递归地尝试每一行的每一个可能的位置,并在放置皇后后检查是否满足条件,最终找到所有可能的解。

二、代码

class Solution
{
public:
    /**
     * 存储所有解的二维字符串向量
     */
    vector<vector<string>> res;

    /**
     * 判断在当前行和列下是否可以放置皇后
     * @param row 当前行
     * @param col 当前列
     * @param chessboard 当前棋盘状态
     * @param n 棋盘的大小
     * @return 如果可以放置返回true,否则返回false
     */
    bool isVaild(int row, int col, vector<string> &chessboard, int n)
    {
        // 检查当前列是否有皇后
        for (int i = 0; i < row; i++) {
            if (chessboard[i][col] == 'Q') {
                return false;
            }
        }
        // 检查左上方向是否有皇后
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if (chessboard[i][j] == 'Q') {
                return false;
            }
        }
        // 检查右上方向是否有皇后
        for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
            if (chessboard[i][j] == 'Q') {
                return false;
            }
        }
        return true;
    }

    /**
     * 回溯算法,尝试所有可能的放置位置
     * @param n 棋盘的大小
     * @param row 当前行
     * @param chessboard 当前棋盘状态
     */
    void backtracking(int n, int row, vector<string> &chessboard)
    {
        // 如果已经放置了n个皇后,则找到一个解,将其添加到结果中
        if (row == n) {
            res.push_back(chessboard);
            return;
        }
        // 尝试在每一列放置皇后
        for (int col = 0; col < n; ++col) {
            // 如果当前位置可以放置皇后
            if (isVaild(row, col, chessboard, n)) {
                // 放置皇后
                chessboard[row][col] = 'Q';
                // 递归尝试下一行
                backtracking(n, row + 1, chessboard);
                // 撤销当前位置,尝试其他位置
                chessboard[row][col] = '.';
            }
        }
    }
    /**
     * 解决N皇后问题
     * @param n 棋盘的大小
     * @return 所有可能的解
     */
    vector<vector<string>> solveNQueens(int n)
    {
        // 清空结果
        res.clear();
        // 初始化棋盘
        vector<string> chessboard(n, string(n, '.'));
        // 开始回溯
        backtracking(n, 0, chessboard);
        return res;
    }
};

三、代码解析

1. 算法工作原理分解
1.1 回溯函数 backtracking
  • 目的:递归地尝试在每一行放置皇后,并通过剪枝操作避免生成无效的解。

  • 实现

    • 终止条件

      • row​ 等于 n​ 时,说明已经成功放置了 n​ 个皇后,此时将当前棋盘状态 chessboard​ 添加到结果集 res​ 中。
    • 选择与递归

      • 遍历当前行的每一列,尝试在每一列放置皇后。
      • 如果当前位置 (row, col)​ 可以放置皇后(即通过 isVaild​ 函数检查),则在棋盘上放置皇后,并递归地尝试在下一行放置皇后。
    • 回溯

      • 在递归调用返回后,撤销当前位置的皇后,尝试其他可能的位置。
1.2 解决N皇后问题函数 solveNQueens
  • 目的:初始化棋盘并调用回溯函数,生成所有可能的解。

  • 实现

    • 初始化

      • 清空结果集 res​。
      • 初始化棋盘 chessboard​,将其所有位置初始化为 '.'​。
    • 调用回溯函数:从第0行开始调用 backtracking​ 函数,尝试在每一行放置皇后。

    • 返回结果:返回生成的所有可能的解。

2. 关键点说明
2.1 路径的选择与回溯
  • 路径chessboard​ 变量用于存储当前棋盘的布局。
  • 选择:每次选择一个可以放置皇后的位置,并在棋盘上放置皇后。
  • 回溯:在递归调用返回后,撤销当前位置的皇后,以便尝试其他可能的位置。
2.2 结果集的存储
  • 结果集res​ 变量用于存储所有符合条件的棋盘布局。
  • 添加条件:在每次递归调用开始时,如果 row​ 等于 n​,则将当前棋盘布局添加到 res​ 中。
2.3 去重操作
  • 去重:通过 isVaild​ 函数确保每一列和每一条斜线上都没有其他皇后,从而避免生成无效的解。

四、复杂度分析

  • 时间复杂度O(N!)

    • 其中 N​ 是棋盘的大小。在最坏情况下,我们需要尝试每一行的每一个可能的位置,因此时间复杂度为 O(N!)​。
  • 空间复杂度O(N)

    • 递归调用栈的深度最多为 N​,因此空间复杂度为 O(N)​。
    • 结果集 res​ 的空间复杂度为 O(N * N!)​,但在通常情况下,我们只考虑递归栈的空间复杂度。

白展堂:人生就是这样,苦和累你总得选一样吧?哪有什么好事都让你一个人占了呢。 ——《武林外传》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值