回溯算法的原理和實現步驟

1.原理

回溯法是一種選優搜索法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術爲回溯法。

在包含問題的所有解的解空間樹中,按照深度優先搜索的策略,從根結點出發深度探索解空間樹。當探索到某一結點時,要先判斷該結點是否包含問題的解,如果包含,就從該結點出發繼續探索下去,如果該結點不包含問題的解,則逐層向其祖先結點回溯。(其實回溯法就是對隱式圖的深度優先搜索算法)。

2.操作

也就是說解決一個回溯問題,實際上就是一個決策樹的遍歷過程。在這個過程中只需要思考三個問題:
(1)路徑:也就是已經做出的選擇;
(2)選擇列表:也就是你當前可以做的選擇;
(3)結束條件:也就是1到達決策樹底層,無法再做選擇的條件
回溯算法框架:

result = []
def backtrack(路徑, 選擇列表):
	if 滿足結束條件:
		result.add(路徑)
		return
	
	for 選擇 in 選擇列表:
		做選擇
		backtrack(路徑, 選擇列表)
		撤銷選擇

核心是for循環裏面的遞歸,在遞歸調用之前做選擇,在遞歸調用之後撤銷選擇。

3.例子

例一:

Leetcode算法題庫裏面的39題:
給定一個無重複元素的數組 candidates 和一個目標數 target ,找出 candidates 中所有可以使數字和爲 target 的組合。candidates 中的數字可以無限制重複被選取。
在這裏插入圖片描述

代碼:

class Solution:
    def combinationSum(self, candidates, target):
        size = len(candidates)
        candidates.sort()
        print(candidates[0])
        res = []
        path = []
        self.backtrack(res, candidates, target, path, size)
        return res


    def backtrack(self, res, candidates, target, path, size):

        if target == 0:
            x = path[:]
            x.sort()
            if x not in res:
                res.append(path[:])
            return
        for index in range(0, size):
            residue = target - candidates[index]
            if residue < 0:  # 剪枝操作,優化代碼
                break
            path.append(candidates[index])
            self.backtrack(res, candidates, residue, path, size)
            path.pop()


if __name__ == '__main__':
    candidates = [2, 3, 6, 7]
    target = 7
    solution = Solution()
    result = solution.combinationSum(candidates, target)
    print(result)

結果:

[[2, 2, 3], [7]]

其中路徑是path,選擇列表是candidates,結束條件是 if target == 0,做選擇用了一個append,撤銷選擇用了一個出棧的操作。因爲candidates中的數據可以無限重複選取,所以每次遞歸的選擇列表都不變。

參考labuladong的博文
Leetcode上的代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章