题目
Leetcode 51. N皇后
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
示例:
输入:4
输出:[
[".Q…", // 解法 1
“…Q”,
“Q…”,
“…Q.”],
["…Q.", // 解法 2
“Q…”,
“…Q”,
“.Q…”]
]
解释: 4 皇后问题存在两个不同的解法。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-queens
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
Leetcode 52. N皇后 II
给定一个整数 n,返回 n 皇后不同的解决方案的数量。
与上一题不同的就是,上一题返回结果是所有皇后的放置方案,这一题不需要确切的放置结果,只需要返回所有放置方案的数量就可以了。
解题
思路
分析题目: 皇后的放置有三个限制条件,就是同一行、同一列和同一个斜线的不能放置。
所以初步思路就是决策树/回溯,一行一行的放置,每一行放置一个保证了同一行不会有两个,然后在往下一行行放置的过程中,遍历每个位置,对每个位置进行选择放置的时候判断当前位置是否有同行/同列/同斜线的已经有皇后了,如果有的话就不能放置了,如果没有,则可以放置,进行下一步回溯。
框架就是:在循环里执行这三步
- 做出当前选择
- 进行下一步决策(递归)
- 撤销当前选择(不影响下次选择),即将第一步做的改变还原
应用到这一题就是在循环里判断当前遍历到的点(i,j)是否能放置,如果能的话开始决策:
- 选择放置当前点(i,j),将当前点的行、列和斜线都标记为已放置
- 进行下一步决策,即放下一个点,即进行下一行进行放置
- 撤销选择, 即将第一步做的标记都撤销
51题答案
这题需要返回的是具体的放置方案,所以有两种解决方案。
- 我们可以用二维数组直接存储每一次决策的过程和结果,在决策的过程中通过在当前决策的二维数组中判断是否有皇后来判断是否能放当前位置,当能放置到最后一行的时候就将放置结果(二维数组)直接存入结果列表中。如下51题代码。
- 利用三个辅助数组,标记某行/某左上右下斜线/某左下右上斜线是否已有皇后(为什么不用行标记?因为决策的时候就是一行一行的往下的),这样避免了每次判断需要在已决策的二维数组中进行当前列和两个斜线的遍历来判断是否有皇后冲突,相当于用空间节省了时间。如下52题代码。
class Solution {
int N;
char[][] board;//模拟棋盘
List<List<String>> schemes = new LinkedList<>();//存放结果
public List<List<String>> solveNQueens(int n) {
//经典的回溯问题
//明确选择:每一行有n个位置可选
//明确约束条件:在某个位置防止皇后后要确保不会被攻击,即他所在行、列和斜线不能在被放了
//明确路径:在某一行摆放皇后时,前面已经摆放了的皇后的位置
//明确结束条件:当每一行都成功放下了一个皇后时,说明得到了一个合法的解法
N = n;
board = new char[N][N];
for(char[] line:board){
//初始化
Arrays.fill(line,'.');
}
backtrack(0);//从第一行开始放皇后
return schemes;