leetcode 51 N皇后

leetcode 51 N皇后

n 皇后問題研究的是如何將 n 個皇后放置在 n×n 的棋盤上,而且使皇后彼此之間不能相互攻擊。算法

上圖爲 8 皇后問題的一種解法。
給定一個整數 n,返回全部不一樣的 n 皇后問題的解決方案。 每一種解法包含一個明確的 n 皇后問題的棋子放置方案,該方案中 'Q' 和 '.' 分別表明了皇后和空位。

示例:數組

輸入: 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

相關文章
相關標籤/搜索