给「代码随想录」一个星标吧!

通知:我将公众号文章和学习相关的资料整理到了Github :https://github.com/youngyangyang04/leetcode-master,方便大家在电脑上学习,可以fork到自己仓库,顺便也给个star支持一波吧!

如果对回溯法理论还不清楚的同学,可以先看这个视频:

第51题. N皇后

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

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

上图为 8 皇后问题的一种解法。

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

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

示例: 输入: 4
输出: [
[".Q..",  // 解法 1
"...Q",
"Q...",
"..Q."],

["..Q.",  // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。

提示:
皇后,是国际象棋中的棋子,意味着国王的妻子。皇后只做一件事,那就是“吃子”。当她遇见可以吃的棋子时,就迅速冲上去吃掉棋子。当然,她横、竖、斜都可走一到七步,可进可退。(引用自 百度百科 - 皇后 )

思路

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

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

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

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

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

51.N皇后

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

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

回溯三部曲

按照我总结的如下回溯模板,我们来依次分析:

void backtracking(参数) {    if (终止条件) {        存放结果;        return;    }    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {        处理节点;        backtracking(路径,选择列表); // 递归        回溯,撤销处理结果    }}
  • 递归函数参数

我依然是定义全局变量二维数组result来记录最终结果。

参数n是棋牌的大小,然后用row来记录当前遍历到棋盘的第几层了。

代码如下:

vector> result;void backtracking(int n, int row, vector& chessboard) {
  • 递归终止条件

在如下树形结构中:

可以看出,当递归到棋盘最底层(也就是叶子节点)的时候,就可以收集结果并返回了。

代码如下:

if (row == n) {    result.push_back(chessboard);    return;}
  • 单层搜索的逻辑

递归深度就是row控制棋盘的行,每一层里for循环的col控制棋盘的列,一行一列,确定了放置皇后的位置。

每次都是要从新的一行的起始位置开始搜,所以都是从0开始。

代码如下:

for (int col = 0; col     if (isValid(row, col, chessboard, n)) { // 验证合法就可以放        chessboard[row][col] = 'Q'; // 放置皇后        backtracking(n, row + 1, chessboard);        chessboard[row][col] = '.'; // 回溯,撤销皇后    }}
  • 验证棋牌是否合法

按照如下标准去重:

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

代码如下:

bool isValid(int row, int col, vector& chessboard, int n) {    int count = 0;    // 检查列for (int i = 0; i         if (chessboard[i][col] == 'Q') {return false;        }    }    // 检查 45度角是否有皇后for (int i = row - 1, j = col - 1; i >=0 && j >= 0; i--, j--) {if (chessboard[i][j] == 'Q') {return false;        }    }    // 检查 135度角是否有皇后for(int i = row - 1, j = col + 1; i >= 0 && j         if (chessboard[i][j] == 'Q') {return false;        }    }return true;}

在这份代码中,细心的同学可以发现为什么没有在同行进行检查呢?

因为在单层搜索的过程中,每一层递归,只会选for循环(也就是同一行)里的一个元素,所以不用去重了。

那么按照这个模板不难写出如下代码:

C++代码

class Solution {private:vector> result;// n 为输入的棋盘大小// row 是当前递归到棋牌的第几行了void backtracking(int n, int row, vector& chessboard) {if (row == n) {        result.push_back(chessboard);return;    }for (int col = 0; col         if (isValid(row, col, chessboard, n)) { // 验证合法就可以放            chessboard[row][col] = 'Q'; // 放置皇后            backtracking(n, row + 1, chessboard);            chessboard[row][col] = '.'; // 回溯,撤销皇后        }    }}bool isValid(int row, int col, vector& chessboard, int n) {    int count = 0;    // 检查列for (int i = 0; i         if (chessboard[i][col] == 'Q') {return false;        }    }    // 检查 45度角是否有皇后for (int i = row - 1, j = col - 1; i >=0 && j >= 0; i--, j--) {if (chessboard[i][j] == 'Q') {return false;        }    }    // 检查 135度角是否有皇后for(int i = row - 1, j = col + 1; i >= 0 && j         if (chessboard[i][j] == 'Q') {return false;        }    }return true;}public:    vector> solveNQueens(int n) {        result.clear();        std::vector<:string> chessboard(n, std::string(n, '.'));        backtracking(n, 0, chessboard);return result;    }};

可以看出,除了验证棋盘合法性的代码,省下来部分就是按照回溯法模板来的。

总结

本题是我们解决棋盘问题的第一道题目。

如果从来没有接触过N皇后问题的同学看着这样的题会感觉无从下手,可能知道要用回溯法,但也不知道该怎么去搜。

「这里我明确给出了棋盘的宽度就是for循环的长度,递归的深度就是棋盘的高度,这样就可以套进回溯法的模板里了」

大家可以在仔细体会体会!

就酱,如果感觉「代码随想录」干货满满,就分享给身边的朋友同学吧,他们可能也需要!

打算从头开始打卡的录友,可以在「算法汇总」这里找到历史文章,很多录友都在从头打卡,你并不孤单!

-------end-------

另外因为公众号改版,时间线被打乱,一些精彩文章大家可能错过了。如果感觉这里的文章对你有帮助,赶紧给「代码随想录」加一个星标吧,方便第一时间阅读文章「代码随想录」期待你的关注!

每天8:35准时推送一道经典算法题目,推送的每道题目都不是孤立的,而是由浅入深,环环相扣,帮你梳理算法知识脉络,轻松学算法!

刷题可以加我微信!右边为个人微信,添加时备注:「简单自我介绍」+「组队刷题」我就知道你[在看]

回溯 皇后 算法笔记_回溯算法:N皇后问题相关推荐

  1. 算法笔记之hoorspool算法

    算法笔记之hoorspool算法 从右往左进行字符扫描,如果所有匹配成功,则找到了匹配的字串,如果遇到不匹配的时候,就需要将模式右移动,这个时候考虑的是文本与模式最后一个字符对齐的文本字符C 当字符不 ...

  2. 回溯 皇后 算法笔记_什么叫回溯算法,一看就会,一写就废

    什么叫回溯算法 对于回溯算法的定义,百度百科上是这样描述的:回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就"回溯"返回, ...

  3. 算法笔记之回溯法(2)

    着色问题 问题分析 假设地图共有7个区域,分别是A/B/C/D/E/F/G,对上面顺序进行编号,每个区域用一个结点表示,相邻的区域有连线,那么地图就转化成一个无向连接图. 算法设计 定义问题的解空间. ...

  4. 算法笔记之回溯法(一)——溯洄从之,道阻且长;溯游从之,宛在水中央。

    回溯法理论基础 回溯法是一种搜索算法,从本质上来说,回溯法是一种穷举法,穷尽其所有可能而举其可行解:尽管回溯法有剪枝等操作,但也只是去除一些明显不可行的部分,仍改变不了回溯法暴力搜索的本质. 虽然回溯 ...

  5. 0027算法笔记——【回溯法】回溯法与装载问题

    1.回溯法 (1)描述:回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法.  (2)原 ...

  6. LQ训练营(C++)学习笔记_枚举算法

    枚举算法 一.枚举算法 1.枚举的概念 2.枚举的题目特点 3.问题描述 4.代码实现 一.枚举算法 1.枚举的概念 枚举就是根据提出的问题,列出该问题所有可能的解,并在逐一列出的过程中,检验每个可能 ...

  7. 迪杰斯特拉算法c++_《算法图解》学习记录7--迪杰斯特拉算法

    本章内容  继续图的讨论,介绍加权图--提高或降低某些边的权重.  介绍狄克斯特拉dijstra算法,让你能够找出加权图中前往X的最短路径.  介绍图中的环,它导致狄克斯特拉算法不管用. 在前一 ...

  8. 【数据结构和算法笔记】KMP算法介绍

    BF暴力算法: 当模式串位i与目标串i比较时两字符不相等,则i的移动方式:i=i-j+1 j的移动方式:j=0   KMP算法简介: ●KMP模式匹配中,当模式串位j与目标串位i比较两字符不相等 i  ...

  9. python贪心算法最短路径_贪心算法---最短路径问题

    一,贪心算法的设计思想 • 从问题的某一个初始解出发逐步逼近给定的目标,每一步都作一个不可回溯的决策,尽可能地求得最好的解.当达到某算法中的某一步不需要再继续前进时,算法停止. 二,贪心算法的基本性质 ...

最新文章

  1. 统计数列中是连续数的个数
  2. jQuery获取CSS样式中的颜色值的问题,不同浏览器格式不同怎么办
  3. 【Maven】maven 插件开发实战
  4. 是是非非本寻常,我们要不要跳槽。
  5. 判断非负整数是否是3的倍数_二、因数与倍数教案
  6. 标题:浅析图卷积神经网络
  7. 2019.01.22【NOIP普及组】模拟赛C组总结
  8. 前端学习(803):字符串拼接和截取
  9. POJ3420 Quad Tiling(模板+矩阵快速幂)
  10. boost学习之BOOST_PP_REPEAT
  11. 集合竞价如何买入_世界上最稳健的抓涨停方法“10分钟集合竞价”选股诀窍,买入直接稳赚10个点,赚到笑...
  12. CSS属性:display详解
  13. 【Django 2021年最新版教程4】为项目添加资源文件(css,js,image)
  14. 第八课 实战重启验证注册机制
  15. 多线程抓取链家网数据
  16. call_user_func_array函数详解
  17. 深度相机原理及坐标系转换
  18. 使用if判断用户名和密码是否正确
  19. QT 代码行统计工具
  20. 5.20爬虫结——Mu

热门文章

  1. 活久见!谷歌开源“大杀器”,CV、NLP都能用!
  2. 再见吧,996!程序员开源考公指南获高赞:三人已成功上岸
  3. 图文并茂!60页PPT《快速入门python数据分析路线》(附链接)
  4. 2400门课:MIT 开放迄今最全 计算机+电气工程课程
  5. 全网最火的Nacos源码构建,你找不到第二个有我仔细的!!
  6. 打印零与奇偶数(多线程)
  7. Python与redis集群进行交互操作
  8. ACMNO.13求Sn=1!+2!+3!+4!+5!+…+n!之值,其中n是一个数字。 输入 n 输出 和 样例输入 5 样例输出 153
  9. Python 的 __name__ 变量,到底是个什么东西?
  10. 值得一看的文本检测方法