(LeetCode)全排列, 回溯法

1. 子集

78. subsets
在這裏插入圖片描述

class Solution(object):
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]

        方法
            回溯法, 循環內遞歸, 即DFS
            https://pic.leetcode-cn.com/a4f4acf7177b6a1131b1ef5da97c1dae218f3c34e9418219055c729c90300122-image.png
            求子集就是在遞歸生成一棵樹, 一條一條路徑、一個一個節點
            遍歷, 當前路徑path增加了各個可能元素後, 再遞歸考慮下個元素
            下個元素的取值範圍很重要
        """
        result = []

        def backtrack(path, idx):  # 已經有path的情況下, 考慮增加第idx位置的元素
            result.append(path)
            for i in range(idx, len(nums)):
                backtrack(path+[nums[i]], i+1)

        backtrack([], 0)  # 初始path爲空集, 考慮增加第0個元素
        return result

2. 全排列

46. permutations
在這裏插入圖片描述

class Solution(object):
    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]

        方法
            回溯法, DFS
            遍歷一棵樹, 類似於求所有子集那道題
            https://pic.leetcode-cn.com/9d228e7ee9c0beceb48983717e253fd0cd6ba96ef76d06758451a1d4af651c36-image.png
            
        """
        result = []

        def backtrack(path):
            if len(path) == len(nums):  # path長度與nums相等時, 輸出
                result.append(path)
                return
            for num in set(nums) - set(path):  # 遍歷所有可以增加的元素(排除掉已經在path裏面的)
                backtrack(path+[num])
        
        backtrack([])  # 從空集開始增加元素
        return result
        

3. 括號生成

22. generate-parentheses
在這裏插入圖片描述

class Solution(object):
    def generateParenthesis(self, n):
        """
        :type n: int
        :rtype: List[str]
        
        方法
            生成潛在的可能結果排列組合, 然後一個一個排除
            排除的過程可以使用輔助棧
        """
        def judge_valid(parenthesis):
            stack = []
            for char in parenthesis:
                if char == '(':
                    stack.append(char)
                else:
                    if not stack:  # 棧爲空就想出, 不合法
                        return False
                    stack.pop()
            return True if not stack else False  # 棧不爲空, 不合法
        
        result = []

        def backtrack(path):
            if len(path) == 2*n:
                if judge_valid(''.join(path)):
                    result.append(''.join(path))
                return
            if path.count('(') < n:  # for循環遞歸被替換成兩個遞歸併列
                backtrack(path+['('])
            if path.count(')') < n:
                backtrack(path+[')'])
        
        backtrack([])
        return result
        

4. 組合總和

39. combination-sum
在這裏插入圖片描述

class Solution(object):
    def combinationSum(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]

        思路
            排列組合, 回溯時限制和不能大於target, 當等於target時輸出
        """
        def backtrack(path, cur_sum):
            if path and cur_sum == target:
                path.sort()
                if str(path) not in tmp_set:
                    result.append(path)
                    tmp_set.add(str(path))
            elif path and cur_sum > target:
                return
            for candidate in candidates:  # 有放回全排列, 注意重複元素
                backtrack(path+[candidate], cur_sum+candidate)
        
        result = []
        tmp_set = set()  # 用於去重, 最終結果裏面[2, 2, 3]與[2, 3, 2]、[3, 2, 2]是同一個
        backtrack([], 0)
        
        return result
        
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章