n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,而且使皇后彼此之间不能相互攻击。算法
示例:数组
输入: 4
输出: [
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不一样的解法。
复制代码
这道题个人思路是回溯+剪枝。
皇后之间不能攻击,西洋的皇后太霸道,不只纵横无忌,还能斜着打,因此这也给了咱们剪枝的手段。咱们选择逐行进行递归,在递归的同时,能够将已肯定位置的皇后所能攻击到的地方标记起来。bash
咱们能够看到,若是(d,8)位置的皇后已经肯定了位置,那么四个方向的延长线就都变成了禁区。把棋盘看作二维数组,(a,8)即为[0][0]位置。app
判断依据:测试
横线上,只须要在肯定一个位置后,直接进行下一行便可。
竖线上,将肯定位置后所在列进行记忆化,以后的位置与出现过的全部列进行比对。
蓝色的“撇”,通过的全部格子有一个共同点,那就是横坐标加上纵坐标的结果是相同的。例如蓝线通过的每一个格子都是3,这个结果只有蓝线上的格子符合。咱们只须要将这个结果记忆化便可。
红色的“捺”,横坐标减去纵坐标的值进行记忆化。ui
上码!spa
func solveNQueens(n int) [][]string {
//n为边长。显而易见,n == 1 皇后只能独坐闺房,n <= 3的时候无解
if n == 1 {
return [][]string{{"Q"}}
}
if n <= 3{
return [][]string{}
}
var re [][]int
// pies为撇,nas为捺,变量名称有点混血,rows保存的是所在行的列坐标
DFS := func(rows []int, pies []int, nas []int, n int){}
DFS = func(rows []int, pies []int, nas []int, n int){
row := len(rows)
//rows的长度 == n 说明已经到了最后一行了,能够return了宝贝
if row == n {
// 此处是由于Go的切片是地址,往结果数组中加的时候必定要复制一份新的,否则会被后
// 序操做改掉。下边注释的是偷懒的写法,会浪费空间哦
newRows := make([]int, len(rows))
copy(newRows,rows)
re = append(re,newRows)
//re = append(re,append([]int{},rows...))
return
}
for col:= 0; col< n; col++ {
flag := true
//此处进行剪枝,按照上边说的进行判断,换成Map来存时间复杂度比较低,
//后边我会分享一下,这样写主要是图个简单,并且测试用例n最大不会超过10。
for k,v := range rows {
if v == col || pies[k] == (row+col-1) || nas[k] == (row-col-1){
flag = false
break
}
}
if flag{
//递归,其实正统的写法应当是先append到切片中,递归,而后从切片中剔除。
//这样写更酷一些。
DFS(append(rows,col),append(pies,(row+col-1)),append(nas,(row-col-1)),n)
}
}
}
DFS([]int{},[]int{},[]int{},n)
return bQ(re,n)
}
//为了知足题意。。。搞成字符串Q。真是画蛇添足哈哈
func bQ (re [][]int,n int) (result [][]string) {
for _,v := range re {
s := []string{}
for _,vv := range v{
str := ""
for i:=0;i<n;i++ {
if i == vv {
str += "Q"
}else{
str += "."
}
}
s = append(s,str)
}
result = append(result,s)
}
return
}
复制代码
OK,咱们能够考虑用map来存储竖、撇、捺,聊胜于无。code
func solveNQueens(n int) [][]string {
if n == 1 {
return [][]string{{"Q"}}
}
if n <= 3{
return [][]string{}
}
var re [][]int
//三个map,shus就是竖,扑面而来的爱国情怀。
shus,pies,nas := make(map[int]bool,n),make(map[int]bool,n),make(map[int]bool,n)
DFS := func(rows []int, n int){}
DFS = func(rows []int, n int){
row := len(rows)
if row == n {
aaaa := make([]int, len(rows))
copy(aaaa,rows)
//re = append(re,append([]int{},rows...))
re = append(re,aaaa)
return
}
for col:= 0; col< n; col++ {
//就是这里了,先把三个map对应位置搞成true,递归,而后搞成false,不影响下个循环,很
//玄幻,可是就是能工做哈哈,多玩玩就能想明白。
if !shus[col] && !pies[row+col-1] && !nas[row-col-1]{
shus[col] = true
pies[row+col-1] = true
nas[row-col-1] = true
DFS(append(rows,col),n)
shus[col] = false
pies[row+col-1] = false
nas[row-col-1] = false
}
}
}
DFS([]int{},n)
return bQ(re,n)
}
复制代码
其实,递归真的是一个很好玩的东西。虽然一不当心就爆栈,但她的思想真的是充满了智慧。她像极了一个老匠人,抽丝剥茧,化繁为易,她又时而涌现出少年才气,看似玩世不恭的外表下跳动着成竹在胸的心。总之,越玩越上瘾啊。cdn
最后,分享一个公众号吧,叫作算法梦想家,来跟我一块儿玩算法,玩音乐,聊聊文学创做,我们一块儿天马行空!blog