【算法】【回溯篇】第4節:全排列問題

本期任務:介紹算法中關於回溯思想的幾個經典問題

【算法】【回溯篇】第1節:八皇后問題

【算法】【回溯篇】第2節:解數獨問題

【算法】【回溯篇】第3節:正則表達式問題

【算法】【回溯篇】第4節:全排列問題

【算法】【回溯篇】第5節:組合問題

【算法】【回溯篇】第6節:子集問題

【算法】【回溯篇】第7節:0-1揹包問題


一、問題描述

問題來源: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種可能,所有可能的擺放方式共有333^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,1,2]
	輸出:
	[
	  [1,1,2],
	  [1,2,1],
	  [2,1,1]
	]

  1. 解決方案:
    基於上文代碼,僅需修改一行即可(即在計算的時候,判斷當前排列是否已經出現過。):
        # if index == self.size:  # 找到一個排列(舊)
        if index == self.size and self.res not in self.ans:  # 找到一個排列(新)
            self.ans.append(list(self.res))
            return
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章