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