leetcode 面试题 08.12. 八皇后

面试题 08.12. 八皇后
设计一种算法,打印 N 皇后在 N × N 棋盘上的各种摆法,其中每个皇后都不同行、不同列,
也不在对角线上。这里的“对角线”指的是所有的对角线,不只是平分整个棋盘的那两条对角线。
注意:本题相对原题做了扩展

示例:

输入:4
输出:[[".Q…","…Q",“Q…”,"…Q."],["…Q.",“Q…”,"…Q",".Q…"]]
解释: 4 皇后问题存在如下两个不同的解法。
[
[".Q…", // 解法 1
“…Q”,
“Q…”,
“…Q.”],

["…Q.", // 解法 2
“Q…”,
“…Q”,
“.Q…”]
]


首先是一种回溯方法,当前位置合格就放入Q,回溯,删除Q。

from typing import List
class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
      out = []
      board = [["."]*n for _ in range(n)]

      def is_vaild(board,row,col, n):
        for i in range(1,min(row,col)+1):
          if board[row-i][col-i] == 'Q':
            return False

        for i in  range(1,min(row+1, n-col)):
          if board[row-i][col+i] == 'Q':
            return False

        for j in range(row):
          if board[j][col] == 'Q':
            return False

        return True

      def backtrack(board, row: int):
        if row == n:
          res = []
          for j in board:
            res.append(''.join(j))
          out.append(res)
          return 
        
        for col in range(n):
          if not is_vaild(board,row,col,n):
            continue
          board[row][col] = 'Q'
          backtrack(board, row+1)
          board[row][col] = '.'
        
      backtrack(board, 0)
      return out

if __name__ == "__main__":
  s = Solution()
  print(s.solveNQueens(8))

经过提交后发现速度不是很快,因为在判断当前位置是否合法的地方存在这大量的计算,所以可以使用一个表格对已经填充过的位置进行记录。在验证的时候就不用一个一个再去判断了。

使用表格记录的回溯方法如下:建议三个表格,分别为左对角线,右对角线,竖直方向。如果有Q值记录在里面就跳出当前的循环,删除上一个Q值,进行回溯。
这种方式相对与之前的逐个比较就会快很多。

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
      out = []
      board = [["."]*n for _ in range(n)]
      def backtrack(left_diagonal,right_diagonal,column):
        row = len(column)
        if row == n:
          res = []
          for j in board:
            res.append(''.join(j))
          out.append(res)
          return 
        
        for col in range(n):
          if col in column or (row - col) in left_diagonal or (row + col) in right_diagonal:
            continue
          board[row][col] = 'Q'
          backtrack(left_diagonal + [row-col],right_diagonal + [row+col],column  + [col])
          board[row][col] = '.'
        
      backtrack([],[],[])
      return out

之后发现每次都需要计算当前column内的个数作为row的行数,所以考虑结合上面两种方法,将row代入到回溯函数中去。这样就不需每次都计算当前的行数值,减少运算。

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
      out = []
      board = [["."]*n for _ in range(n)]
      def backtrack(board, row: int,left_diagonal,right_diagonal,column):
        if row == n:
          res = []
          for j in board:
            res.append(''.join(j))
          out.append(res)
          return 
        
        for col in range(n):
          if col in column or (row - col) in left_diagonal or (row + col) in right_diagonal:
            continue
          board[row][col] = 'Q'
          backtrack(board, row+1,left_diagonal + [row-col],right_diagonal + [row+col],column  + [col])
          board[row][col] = '.'
        
      backtrack(board, 0,[],[],[])
      return out

你可能感兴趣的:(leetcode)