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 皇后问题存在两个不同的解法。
复制代码

这道题我的思路是回溯+剪枝。
皇后之间不能攻击,西洋的皇后太霸道,不仅纵横无忌,还能斜着打,所以这也给了我们剪枝的手段。我们选择逐行进行递归,在递归的同时,可以将已确定位置的皇后所能攻击到的地方标记起来。

我们可以看到,如果(d,8)位置的皇后已经确定了位置,那么四个方向的延长线就都变成了禁区。把棋盘看做二维数组,(a,8)即为[0][0]位置。

判断依据:

横线上,只需要在确定一个位置后,直接进行下一行即可。
竖线上,将确定位置后所在列进行记忆化,之后的位置与出现过的所有列进行比对。
蓝色的“撇”,经过的所有格子有一个共同点,那就是横坐标加上纵坐标的结果是相同的。例如蓝线经过的每个格子都是3,这个结果只有蓝线上的格子符合。我们只需要将这个结果记忆化即可。
红色的“捺”,横坐标减去纵坐标的值进行记忆化。

上码!

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;iif i == vv {
                    str += "Q"
                }else{
                    str += "."
                }
            }
            s = append(s,str)
        }
        result = append(result,s)
    }
    return
} 
复制代码

OK,我们可以考虑用map来存储竖、撇、捺,聊胜于无。

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)
}
复制代码

其实,递归真的是一个很好玩的东西。虽然一不小心就爆栈,但她的思想真的是充满了智慧。她像极了一个老匠人,抽丝剥茧,化繁为易,她又时而涌现出少年才气,看似玩世不恭的外表下跳动着胸有成竹的心。总之,越玩越上瘾啊。

最后,分享一个公众号吧,叫做算法梦想家,来跟我一起玩算法,玩音乐,聊聊文学创作,咱们一起天马行空!

转载于:https://juejin.im/post/5cb340e5f265da03555c7148

你可能感兴趣的:(leetcode 51 N皇后)