題目介紹:51. N皇后
先給出答案:
class Solution(object):
def solveNQueens(self, n):
"""
:type n: int
:rtype: List[List[str]]
使用最基礎的回溯算法,決策樹遍歷
"""
import copy
if n == 0: return []
res = []
path = [['.' for _ in range(n)] for _ in range(n)] # 申請列表類型變量,因爲python字符串不能直接修改某個字符
direction = [[-1, -1, -1, 0, 0, 1, 1, 1],
[-1, 0 ,1, -1, 1, -1, 0, 1]] # 分別表示上下左右 左上 左下 右上 右下
# 判斷當前位置是否合法,此處可以優化,因爲當前元素上方、左下角和右上角的元素不需要判斷
def can(i, j):
for biger in range(1, n+1): # 一層一層向8個方向擴展,像泛起的水花
for k in range(8):
nexti = i + direction[0][k]*biger
nextj = j + direction[1][k]*biger
if nexti >= 0 and nexti < n and nextj >= 0 and nextj < n:
if path[nexti][nextj] == 'Q':
return False
return True
# 判斷第i層可以放置的所有位置(當前行的所有位置),i從0開始
def back_track(path, i):
# 結束條件
if i == n:
res.append(copy.deepcopy(path)) # 注意使用深拷貝
return
for j in range(n): # 遍歷當前層的所有選擇
if can(i, j) == False: # 判斷第i層的j位置是否合法,進行剪枝操作
continue
path[i][j] = 'Q' # 做選擇
back_track(path, i+1) # 回溯
path[i][j] = '.' # 撤銷選擇
back_track(path, 0)
str_res = [[''.join(line) for line in m] for m in res] # 轉換格式
return str_res
# s = Solution()
# print(s.solveNQueens(4))
# 小實驗用於測試
# path = [['.', '.' , '.'], ['.', '.' , '.']]
# a = path[:][:]
# path[1][0] = 'O'
# print(a)
# a = '....'
# a[1] = 'o'
# print(a)
- 回溯實際上是遍歷決策樹,通過遍歷每一種情況,從而確定哪些路徑符合要求,其中時間複雜度爲O(n!),比如在不含重複元素的“全排列”中,共有n!種解。這也是回溯算法的⼀個特點,不像動態規劃存在重疊⼦問題可以優化,回溯算法就是純暴⼒窮舉,複雜度⼀般都很⾼。
- 基本代碼流程
result = []
def backtrack(路徑, 選擇列表):
if 滿⾜結束條件:
result.add(路徑)
return
for 選擇 in 選擇列表:
做選擇 # 對應樹的前序遍歷
backtrack(路徑, 選擇列表)
撤銷選擇 # 對應樹的後續遍歷
ps:前序遍歷的代碼在進⼊某⼀個樹的節點之前的那個時間點執⾏,後序遍歷代碼在離開某個節點之後的那個時間點執⾏。我們要在遞歸之前做出選擇,在遞歸之後撤銷剛纔的選擇。