在我的上一篇文章[《前端电商 sku 的全排列算法很难吗?学会这个套路,彻底掌握排列组合。》] 中详细的讲解了排列组合的递归回溯解法,相信看过的小伙伴们对这个套路已经有了一定程度的掌握(没看过的同学快回头学习~)。
昨晚正好在看字节跳动的招聘直播,弹幕里有一些同学提到了面试时候考到了「N 皇后」问题,他没有答出来。这是一道 LeetCode 上难度为 hard 的题目。
听起来很吓人,但是看过我上一篇文章的同学应该还记得我有提到过,我解决电商 sku 问题用的是排列组合的万能模板,这个万能模板能否用来解决这个经典的计算机问题「N 皇后」呢?答案是肯定的。
先来看问题,其实问题不难理解:
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
示例:
输入: 4
输出: [
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
提示:
皇后,是国际象棋中的棋子,意味着国王的妻子。皇后只做一件事,那就是“吃子”。当她遇见可以吃的棋子时,就迅速冲上去吃掉棋子。当然,她横、竖、斜都可走一到七步,可进可退。(引用自 百度百科 - 皇后 )
LeetCode 原题地址[1]
乍一看这种选出全部方案的问题有点难找到头绪,但是其实仔细看一下,题目已经限定了皇后之间不能互相攻击,转化成代码思维的语言其实就是说每一行只能有一个皇后,每条对角线上也只能有一个皇后,
也就是说:
[
'Q', 0
'Q', 0
]
2 . 在左上 -> 右下的对角线上,错。
[
'Q', 0
0, 'Q'
]
2 . 在左下 -> 右上的对角线上,错。
[
0, 'Q'
'Q', 0
]
那么以这个思路为基准,我们就可以把这个问题转化成一个「逐行放置皇后」的问题,思考一下递归函数应该怎么设计?
对于 n皇后
的求解,我们可以设计一个接受如下参数的函数:
rowIndex
参数,代表当前正在尝试第几行放置皇后。prev
参数,代表之前的行已经放置的皇后位置,比如 [1, 3]
就代表第 0 行(数组下标)的皇后放置在位置 1,第 1 行的皇后放置在位置 3。当 rowIndex === n
即说明这个递归成功的放置了 n 个皇后,一路畅通无阻的到达了终点,每次的放置都顺利的通过了我们的限制条件,那么就把这次的 prev
做为一个结果放置到一个全局的 res
结果数组中。
这里我尝试用工具画出了 4皇后
的其中的一个解递归的树状图,第一行我直接选择了以把皇后放在2
为起点,省略了以 放在1
、放在3
、放在4
为起点的树状图,否则递归树太大了图片根本放不下。
注意这里的 放在x
,为了方便理解,这个 x
并不是数组下标,而是从 1 开始的计数。
在这次递归之后,就求出了一个结果:[1, 3, 0, 2]
。
你可以在纸上按照我的这种方式继续画一画尝试以其他起点开始的解法,来看看这个算法的具体流程。
理想总是美好的,虽然目前为止我们的思路很清晰了,但是具体的编码还是会遇到几个头疼的问题的。
当前一行已经落下一个皇后之后,下一行需要判断三个条件:
难点在于判断对角线上是否摆放过皇后了,其实找到规律后也不难了,看图:
对角线1
:
直接通过这个点的横纵坐标 rowIndex + columnIndex
相加,相等的话就在同在对角线 1 上:
对角线1
对角线2
:
直接通过这个点的横纵坐标 rowIndex - columnIndex
相减,相等的话就在同在对角线 2 上:
对角线2
所以:
columns
数组记录摆放过的列下标,摆放过后直接标记为 true 即可。dia1
数组记录摆放过的对角线 1下标,摆放过后直接把下标 rowIndex + columnIndex
标记为 true 即可。dia2
数组记录摆放过的对角线 1下标,摆放过后直接把下标 rowIndex - columnIndex
标记为 true 即可。prev
代表每一行中皇后放置的列数,比如 prev[0] = 3
代表第 0 行皇后放在第 3 列,以此类推。有了这几个辅助知识点,就可以开始编写递归函数了,在每一行,我们都不断的尝试一个坐标点,只要它和之前已有的结果都不冲突,那么就可以放入数组中作为下一次递归的开始值。
这样,如果递归函数顺利的来到了 rowIndex === n
的情况,说明之前的条件全部满足了,一个 n皇后
的解就产生了。把 prev
这个一维数组通过辅助函数恢复成题目要求的完整的「二维数组」即可。
/**
* @param {number} n
* @return {string[][]}
*/
let solveNQueens = function (n) {
let res = []
// 已摆放皇后的的列下标
let columns = []
// 已摆放皇后的对角线1下标 左下 -> 右上
// 计算某个坐标是否在这个对角线的方式是「行下标 + 列下标」是否相等
let dia1 = []
// 已摆放皇后的对角线2下标 左上 -> 右下
// 计算某个坐标是否在这个对角线的方式是「行下标 - 列下标」是否相等
let dia2 = []
// 在选择当前的格子后 记录状态
let record = (rowIndex, columnIndex, bool) => {
columns[columnIndex] = bool
dia1[rowIndex + columnIndex] = bool
dia2[rowIndex - columnIndex] = bool
}
// 尝试在一个n皇后问题中 摆放第index行内的皇后位置
let putQueen = (rowIndex, prev) => {
if (rowIndex === n) {
res.push(generateBoard(prev))
return
}
// 尝试摆第index行的皇后 尝试[0, n-1]列
for (let columnIndex = 0; columnIndex < n; columnIndex++) {
// 在列上不冲突
let columnNotConflict = !columns[columnIndex]
// 在对角线1上不冲突
let dia1NotConflict = !dia1[rowIndex + columnIndex]
// 在对角线2上不冲突
let dia2NotConflict = !dia2[rowIndex - columnIndex]
if (columnNotConflict && dia1NotConflict && dia2NotConflict) {
// 都不冲突的话,先记录当前已选位置,进入下一轮递归
record(rowIndex, columnIndex, true)
putQueen(rowIndex + 1, prev.concat(columnIndex))
// 递归出栈后,在状态中清除这个位置的记录,下一轮循环应该是一个全新的开始。
record(rowIndex, columnIndex, false)
}
}
}
putQueen(0, [])
return res
}
// 生成二维数组的辅助函数
function generateBoard(row) {
let n = row.length
let res = []
for (let y = 0; y < n; y++) {
let cur = ""
for (let x = 0; x < n; x++) {
if (x === row[y]) {
cur += "Q"
} else {
cur += "."
}
}
res.push(cur)
}
return res
}
对递归回溯的相似 LeetCode 题型感兴趣的同学,可以去我维护的 力扣题解-递归与回溯[2] 这个 Github 仓库分类下查看其它的经典相似题目,先尝试自己用我的两篇递归回溯文章中的思路求解,如果还是答不出来的话,就去看题解总结归纳,直到你能真正的自己做出类似的题型为止。
至此为止,年轻人的第一道 hard 题就解出来了,是不是有种任督二脉打通的感觉呢?
递归回溯的问题本质上就是,递归进入下一层后,如果发现不满足条件,就通过 return 等方式回溯到上一层递归,继续寻求合适的解。
掌握了这个思路以后,相信你在现实编码中遇到的很多递归难题都可以轻松的降维打击,迎刃而解了。
也祝正在筹备换工作的小伙伴们顺利通过面试笔试的厮杀,拿到理想的 offer,大家加油。
[1]LeetCode 原题地址: https://leetcode-cn.com/problems/n-queens
[2]力扣题解-递归与回溯: https://github.com/sl1673495/leetcode-javascript/issues?q=is%3Aopen+is%3Aissue+label%3A%E9%80%92%E5%BD%92%E4%B8%8E%E5%9B%9E%E6%BA%AF
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/4d-fdX8wyjs1LS-mo9TQFg
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。