Leetcode日记:51&52.N皇后问题
题目
The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.
Given an integer n, return all distinct solutions to the n-queens puzzle.
Each solution contains a distinct board configuration of the n-queens’ placement, where ‘Q’ and ‘.’ both indicate a queen and an empty space respectively.
Example:
1 | Input: 4 |
题目分析
这就是这次回溯问题的最终难题————经典的八皇后问题,题目主要的要求就是在摆N个皇后之后,皇后之间不能相互碰到。
这也要求我们利用回溯思想解决问题,当然不用回溯也是可以的,但是回溯的精妙之处在于其简洁,明了。让我们看看代码是如何实现的吧。
代码
1 | class Solution { |
代码分析
回溯思想
这道题的回溯思想和之前我们两道题基本一致,并没有过于难的地方:
结构::
- 递归(迭代):这道题本身就是DFS问题,首先从第一行第一个开始,试着放一个皇后,接下来把相关信息放入,继续迭代(层数加一,
rowIndex+1
),当发现满足条件时存入数组并返回。 - 条件:当放入的皇后数量等于目标数便可存入,当无解后会自动结束。在每一次布局时,共同维护着三个Boolean数组,来判断是否皇后会打架。(详细见下文)
- 结束:当一次迭代执行完毕之后,不管这个方法成功与否,都把当前得到的排布的最后一行删掉
list.remove(list.size()-1)
,并初始化这一行,并且还原Boolean数组,重新安排这一行的下一种布局(回溯)。
关于打架的判断
上文提到,每一次布局都会有与之对应的三个Boolean数组,这个数组便是检测在这一列、副对角线,主对角线上的皇后是否产生打架,这个规则不容易想,首先,我们以数组的形式来模拟棋盘:
1 | [0,0][0,1][0,2][0,3][0,4] |
我们来找一下:visited[i]
是与之对应的列,这个很显然。dia1[rowIndex+i]
说的是副对角线,可以观察到副对角线上,行(rowIndex
)与列(i
)之和是一样的。dia2[rowIndex-i+n-1]
说的是副对角线,仔细观察发现主对角线上,行(rowIndex
)与列(i
)之差是一样的,但是为了避免出现数组索引为负数的情况,代码特意在后面+n-1
。
关于回溯时的状态重置
回溯状态重置这个问题已经是老生常谈了,但是仍然要引起重视,这是很容易遗漏的一点。
首先,回溯之前,要把之前迭代的不符合要求或者已经存入的上一层内容清空重置(谨记只是上一层内容),反映到此题上就是
1 | list.remove(list.size()-1); |
相比之前几道题已经讲过很多次了。
还有就是要把判断状态表重置,反映在此题就是
1 | visited[i] = false; |
52题简要说明
这道题比第一个简单很多,只要求输出有多少种摆法。只需要在原看来代码的基础上删去不必要的List<List<String>> result
,然后添加一个int型变量,得到满足条件的结果就+1就可以了。
更多回溯算法
更多关于回溯算法的问题请转到回溯算法标签