本期任務:介紹算法中關於回溯思想的幾個經典問題
一、問題描述
問題來源:LeetCode 46. 全排列
給定一個 沒有重複 數字的序列,返回其所有可能的全排列。
示例:
輸入: [1,2,3]
輸出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
二、算法思路
- 使用回溯思想,暴力窮舉,每一個位置都可能有1-3共3種可能,所有可能的擺放方式共有,窮舉過程遵循深度優先搜索規則。
- 剪枝策略:維護一個existed數組,用於記錄每個數字的出現與否,再次出現則跳過。
- 結算情形:所有數字都已遍歷
三、Python代碼實現
class AllPermutation():
def __init__(self, array):
self.arr = array
self.size = len(self.arr)
self.res = [-1] * self.size # 記錄當前排列
self.ans = []
self.visited = [0] * self.size # 記錄每個數字的被訪問情況
def all_permutation(self, index=0):
"""回溯的主邏輯"""
if index == self.size: # 找到一個排列
self.ans.append(list(self.res))
return
for i, v in enumerate(self.arr): # 每一個給位置都有三種可能
if not self.visited[i]: # 當前位置未被訪問過
self.res[index] = v
self.visited[i] = 1
self.all_permutation(index + 1)
self.visited[i] = 0 # 由於回溯過程對三個二維數組進行了修改,故回溯完成需要對稱復原。
def main():
ap = AllPermutation([1, 2, 3])
ap.all_permutation()
print(ap.ans)
if __name__ == '__main__':
main()
運行結果
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
四、問題變形
問題來源:LeetCode 47. 全排列II
- 題目描述
給定一個可包含重複數字的序列,返回所有不重複的全排列。
示例:
輸入: [1,1,2]
輸出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
- 解決方案:
基於上文代碼,僅需修改一行即可(即在計算的時候,判斷當前排列是否已經出現過。):
# if index == self.size: # 找到一個排列(舊)
if index == self.size and self.res not in self.ans: # 找到一個排列(新)
self.ans.append(list(self.res))
return