n皇后问题是将n个皇后放置在n*n的棋盘上,皇后彼此之间不能相互攻击(任意两个皇后不能位于同一行,同一列,同一斜线)。

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

每个解决方案包含一个明确的n皇后放置布局,其中“Q”和“.”分别表示一个女王和一个空位置。

在线评测地址:

LintCode 领扣​

样例1:

输入:1
输出:
[["Q"]]

样例2:

输入:4
输出:
[
// Solution 1
[".Q..",
"...Q",
"Q...",
"..Q."
],
// Solution 2
["..Q.",
"Q...",
"...Q",
".Q.."
]
]

算法:dfs(回溯法)

题目分析

这个问题要求把n个皇后放在一个nXn的棋盘上,使得任何两个皇后都不能相互攻击,即它们不能同行,不能同列,也不能位于同一条对角线上。对于n=1,问题的解很简单,而且很容易看出对于n=2和n=3来说,这个问题是无解的。所以我们考虑4皇后问题,并用回溯法对它求解。

算法思路

  • 因为每个皇后都必须分别占据一行,我们需要做的不过是棋盘上的每个皇后分配一列。
  • 下面我们用4皇后的求解过程来讲解算法思路:

从空棋盘开始,然后把皇后1 放到它所在行的第-一个可能位置上,也就是第一-行第一列。对于皇后2,在经过第-列和第二列的失败尝试之后,我们把它放在第一个可能的位置,就是格子(2, 3),位于第二行第三列的格子。这被证明是一个死胡同,因为皇后3将没有位置可放。所以,该算法进行回溯,把皇后2放在下一个可能位置(2,4)上。这样皇后3就可以放在(3, 2),这被证明是另一个死胡同。该算法然后就回溯到底,把皇后1移到(1,2)。 接着皇后2到(2,4), 皇后3到(3,1), 而皇后4到(4, 3), 这就是该问题的一个解。

  • 整个过程实际上就是一个状态树的遍历过程
  • 下图为状态树

算法:dfs(回溯法)

题目分析

这个问题要求把n个皇后放在一个nXn的棋盘上,使得任何两个皇后都不能相互攻击,即它们不能同行,不能同列,也不能位于同一条对角线上。对于n=1,问题的解很简单,而且很容易看出对于n=2和n=3来说,这个问题是无解的。所以我们考虑4皇后问题,并用回溯法对它求解。

算法思路

  • 因为每个皇后都必须分别占据一行,我们需要做的不过是棋盘上的每个皇后分配一列。
  • 下面我们用4皇后的求解过程来讲解算法思路:

从空棋盘开始,然后把皇后1 放到它所在行的第-一个可能位置上,也就是第一-行第一列。对于皇后2,在经过第-列和第二列的失败尝试之后,我们把它放在第一个可能的位置,就是格子(2, 3),位于第二行第三列的格子。这被证明是一个死胡同,因为皇后3将没有位置可放。所以,该算法进行回溯,把皇后2放在下一个可能位置(2,4)上。这样皇后3就可以放在(3, 2),这被证明是另一个死胡同。该算法然后就回溯到底,把皇后1移到(1,2)。 接着皇后2到(2,4), 皇后3到(3,1), 而皇后4到(4, 3), 这就是该问题的一个解。

  • 整个过程实际上就是一个状态树的遍历过程
  • 下图为状态树

代码思路

  • 按行摆放,在确定一个皇后应该摆的列时,需要检查当前列是否合法,如果合法,则将皇后放置在当前位置,并进行递归,回溯。每行都摆满皇后时,则产生了一种解法,将所有解法收集并返回。
  • 合法性判断方法:当前将要摆放皇后的位置和其他已摆放皇后的位置不能在同一列,且不能在同一条斜线上。这里判断是否在同一条斜线上可以通过两个皇后的位置横坐标之差和纵坐标之差的绝对值是否相等来判断。

复杂度分析

  • 空间复杂度:O(N!)
  • 时间复杂度:O(N!)
  • 放置第一个皇后有 N 种可能,放置两个皇后不超过N(N-2)种可能,放置三个皇后不超过N(N - 2)(N - 4)种可能 ,以此类推。
class Solution {
/**
* Get all distinct N-Queen solutions
* @param n: The number of queens
* @return: All distinct solutions
* For example, A string '...Q' shows a queen on forth position
*/
List<List<String>> solveNQueens(int n) {
// result用于存储答案
List<List<String>> results = new ArrayList<>();
if (n <= 0) {
return results;
} search(results, new ArrayList<Integer>(), n);
return results;
} // search函数为搜索函数,n表示已经放置了n个皇后,cols 表示每个皇后所在的列
private void search(List<List<String>> results, List<Integer> cols, int n) {
// 若已经放置了n个皇后表示出现了一种解法,绘制后加入答案result
if (cols.size() == n) {
results.add(Draw(cols));
return;
}
// 枚举当前皇后放置的列,若不合法则跳过
for (int colIndex = 0; colIndex < n; colIndex++) {
if (!isValid(cols, colIndex)) {
continue;
}
// 若合法则递归枚举下一行的皇后
cols.add(colIndex);
search(results, cols, n);
cols.remove(cols.size() - 1);
}
} // isValid函数为合法性判断函数
private boolean isValid(List<Integer> cols, int col) {
int row = cols.size();
for (int rowIndex = 0; rowIndex < cols.size(); rowIndex++) {
//若有其他皇后在同一列或同一斜线上则不合法
if (cols.get(rowIndex) == col) {
return false;
}
if (row + col == rowIndex + cols.get(rowIndex)) {
return false;
}
if (row - col == rowIndex - cols.get(rowIndex)) {
return false;
}
}
return true;
}
// Draw函数为将 cols 数组转换为答案的绘制函数
private List<String> Draw(List<Integer> cols) {
List<String> result = new ArrayList<>();
for (int i = 0; i < cols.size(); i++) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < cols.size(); j++) {
sb.append(j == cols.get(i) ? 'Q' : '.');
}
result.add(sb.toString());
}
return result;
}
}

更多题解参考:

九章算法 - 帮助更多中国人找到好工作,硅谷顶尖IT企业工程师实时在线授课为你传授面试技巧​

【LeetCode/LintCode】丨Google面试题:N皇后问题的更多相关文章

  1. [leetcode/lintcode 题解] Google面试题:合法组合

    给一个单词s,和一个字符串集合str.这个单词每次去掉一个字母,直到剩下最后一个字母.求验证是否存在一种删除的顺序,这个顺序下所有的单词都在str中.例如单词是’abc’,字符串集合是{‘a’,’ab ...

  2. [leetcode/lintcode 题解] 微软面试题:股票价格跨度

    编写一个 StockSpanner 类,它收集某些股票的每日报价,并返回该股票当日价格的跨度. 今天股票价格的跨度被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,包括今天). 例如 ...

  3. [leetcode/lintcode 题解] Amazon面试题:连接棒材的最低费用

    为了装修新房,你需要加工一些长度为正整数的棒材 sticks. 如果要将长度分别为 X 和 Y 的两根棒材连接在一起,你需要支付 X + Y 的费用. 由于施工需要,你必须将所有棒材连接成一根. 返回 ...

  4. [leetcode/lintcode 题解] 谷歌面试题:找出有向图中的弱连通分量

    请找出有向图中弱连通分量.图中的每个节点包含 1 个标签和1 个相邻节点列表.(有向图的弱连通分量是任意两点均有有向边相连的极大子图) 将连通分量内的元素升序排列. 在线评测地址:https://ww ...

  5. [leetcode/lintcode 题解] 微软面试题:公平索引

    现在给你两个长度均为N的整数数组 A 和 B. 当(A[0]+...A[K-1]),(A[K]+...+A[N-1]),(B[0]+...+B[K-1]) 和 (B[K]+...+B[N-1])四个和 ...

  6. [leetcode/lintcode 题解] 微软 面试题:实现 Trie(前缀树)

    实现一个 Trie,包含 ​insert​, ​search​, 和 ​startsWith​ 这三个方法.   在线评测地址:领扣题库官网     样例 1: 输入:    insert(" ...

  7. leetcode & lintcode for bug-free

    刷题备忘录,for bug-free leetcode 396. Rotate Function 题意: Given an array of integers A and let n to be it ...

  8. leetcode & lintcode 题解

    刷题备忘录,for bug-free 招行面试题--求无序数组最长连续序列的长度,这里连续指的是值连续--间隔为1,并不是数值的位置连续 问题: 给出一个未排序的整数数组,找出最长的连续元素序列的长度 ...

  9. 数组中第K小的数字(Google面试题)

    http://ac.jobdu.com/problem.php?pid=1534 题目1534:数组中第K小的数字 时间限制:2 秒 内存限制:128 兆 特殊判题:否 提交:1120 解决:208 ...

随机推荐

  1. 如何将返回的JSon字符串用MAP格式读取

    语法是这样: ObjectMapper mapper = new ObjectMapper(); Map resultMap=null; resultMap = mapper.readValue(in ...

  2. kafka-clients 1.0 高阶API消费消息(未完)

    消费消息的请求(按序) org/apache/kafka/common/requests/RequestHeader org/apache/kafka/common/requests/ApiVersi ...

  3. pyttsx3 的使用教程

    import pyttsx3 def use_pyttsx3(): # 创建对象 engine = pyttsx3.init() # 获取当前语音速率 rate = engine.getPropert ...

  4. python 05 列表 元组 (序列)

    循环(loop),指的是在满足条件的情况下,重复执行同一段代码.比如,while语句. [ 循环则技能对应集合,列表,数组等,也能对执行代码进行操作.] 迭代(iterate),指的是按照某种顺序逐个 ...

  5. extJS--尚

    ExtJS依赖JavaScript,JavaScript推荐两本书:<JavaScript高级程序设计>初阶阶段, <JavaScript设计模式>中级阶段 fun1();// ...

  6. Jmeter 常用函数(23)- 详解 __longSum

    如果你想查看更多 Jmeter 常用函数可以在这篇文章找找哦 https://www.cnblogs.com/poloyy/p/13291704.htm 作用 计算两个或多个长值的和 注意 当值不在 ...

  7. Prefrontal cortex as a meta-reinforcement learning system

    郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! Nature Neuroscience, 2018 Abstract 在过去的20年中,基于奖励的学习的神经科学研究已经集中在经典模型上, ...

  8. SPSSAU数据分析思维培养系列3:分析思路

    本文章为SPSSAU数据分析思维培养的第3期文章. 上文讲解如何选择正确的分析方法,除了有正确的分析方法外,还需要把分析方法进行灵活运用.拿到一份数据,应该如何进行分析,总共有几个步骤,第一步第二步应 ...

  9. 产品经理培训教程视频大全与模板Axure rp9与8视频教程元件库模板

    注意:请仔细阅读购买,一旦发货百度网盘链接不能退~ 自动发邮件到买家留言处的邮箱,或注册淘宝时的邮箱自动通过旺旺给您发货还可以访问网页提取链接自助提取(复制到浏览器): http://4k5.cn/V ...

  10. 如何通过seo技术提高网站对用户的友好度

    http://www.wocaoseo.com/thread-129-1-1.html    今天的天气又是29度,眼看着满大街的人都穿着短袖和衬衣了,自己也再不能穿个厚厚的外套出去了,要不会被别人笑 ...