「アルゴリズムクリアランスへの道」-第15章 バックトラッキング手法

「アルゴリズムクリアへの道」の学習ノート、問題を磨く自分のプロセスを記録します。詳細な内容については、著者の本を購入してください。

フルアレイ

質問 46
繰り返しの数値を含まない配列 nums が与えられた場合、その可能なすべての順列を返します。回答は任意の順序で返すことができます。

class Solution:
    def permute(self, nums: list[int]) -> list[list[int]]:
        
        res = list()
        used = set()
        n = len(nums)

        def dfs(path: list[int]):
            
            if len(path) == n:
                res.append(path[:]) # 加入的是拷贝不是引用
                return
            for i in range(n):
                if i not in used:
                    used.add(i)
                    path.append(nums[i])
                    dfs(path)
                    path.pop()
                    used.remove(i)
            
        dfs([])
        return res

nums = [1,2,3]
solu = Solution()
solu.permute(nums)
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

フルアレンジⅡ

Lituo の質問 47
繰り返しの数値を含むことができるシーケンス nums を指定すると、繰り返されないすべての完全な順列を任意の順序で返します。

class Solution:
    def permuteUnique(self, nums: list[int]) -> list[list[int]]:

        res = list()
        used = set()
        n = len(nums)
        nums.sort() # 提前排序

        def dfs(path: list[int]):
            
            if len(path) == n:
                res.append(path[:])
                return

            for i in range(n):
                # 同一个位置数字不能相同,i-1 not in used 表明这个位置i-1已经待过
                if i > 0 and nums[i] == nums[i-1] and i-1 not in used:
                    continue 
                if i not in used:
                    used.add(i)
                    path.append(nums[i])
                    dfs(path)
                    path.pop()
                    used.remove(i)
            
        dfs([])
        return res

nums = [1,1,2]
solu = Solution()
solu.permuteUnique(nums)
[[1, 1, 2], [1, 2, 1], [2, 1, 1]]

合計

質問 39:
繰り返し要素のない整数配列の候補と整数のターゲットを与え、数値の合計がターゲットの数値になるような候補のさまざまな組み合わせをすべて見つけて、それらをリスト形式で返します。これらの組み合わせは任意の順序で返すことができます。

同じ候補数を無制限に繰り返し選択できます。少なくとも 1 つの数字の選択された数字が異なる場合、2 つの組み合わせは異なります。

特定の入力について、ターゲットとなるさまざまな組み合わせの合計が 150 未満であることが保証されます。

出典: LeetCode
リンク: https://leetcode.cn/problems/combination-sum
著作権は Leetcode.com に属します。営利目的での転載の場合は正式な許諾を得た方へ、非営利での転載の場合は出典を明記の上、ご連絡ください。

# 无for循环写法,必须先排序
class Solution:
    def combinationSum(self, candidates: list[int], target: int) -> list[list[int]]:
        
        res = list()
        n = len(candidates)
        candidates.sort()

        def dfs(idx: int, cur: int, path: list[int]):

            if cur == 0: # 和为target
                res.append(path[:])
                return
            elif idx == n: # 遍历结束
                return
            
            if candidates[idx] <= cur:
                path.append(candidates[idx])
                dfs(idx, cur-candidates[idx], path)
                path.pop()
                dfs(idx+1, cur, path)
            else: # 没必要继续遍历
                return

        dfs(0, target, list())
        return res

candidates, target = [2,3,6,7], 7
solu = Solution()
solu.combinationSum(candidates, target)
[[2, 2, 3], [7]]
# for循环写法,是否排序都可
class Solution:
    def combinationSum(self, candidates: list[int], target: int) -> list[list[int]]:
        
        res = list()
        n = len(candidates)

        def dfs(idx: int, cur: int, path: list[int]):

            if cur == 0: # 和为target
                res.append(path[:])
                return
            
            for idx in range(idx, n):
        
                if candidates[idx] <= cur:
                    path.append(candidates[idx])
                    dfs(idx, cur-candidates[idx], path)
                    path.pop()

        dfs(0, target, [])
        return res


candidates, target = [2,3,6,7], 7
solu = Solution()
solu.combinationSum(candidates, target)
[[2, 2, 3], [7]]

ポートフォリオサムⅡ

質問 40 を確認してください
。一連の候補数値の候補とターゲット数値ターゲットが与えられた場合、数値の合計をターゲットにすることができる候補内のすべての組み合わせを見つけてください。

候補内の各番号は、各組み合わせで 1 回のみ使用できます。

注: ソリューション セットには重複した組み合わせを含めることはできません。

出典: LeetCode
リンク: https://leetcode.cn/problems/combination-sum-ii
著作権は LeetCode.com に属します。営利目的での転載の場合は正式な許諾を得た方へ、非営利での転載の場合は出典を明記の上、ご連絡ください。

# 不使用used的写法,依据i > idx来判断
class Solution:
    def combinationSum2(self, candidates: list[int], target: int) -> list[list[int]]:
     
        res = list()
        n = len(candidates)
        candidates.sort()
  

        def dfs(idx: int, cur: int, path: list[int]):

            if cur == 0: # 和为target
                res.append(path[:])
                return
            
            for i in range(idx, n):
                # for循环中去重,这里意味着舍弃了i-1所以不能再加入i
                if i > idx and candidates[i] == candidates[i-1]:
                    continue
                if candidates[i] <= cur:
                    path.append(candidates[i])
                    dfs(i+1, cur-candidates[i], path) # 每次进入下一层时不再考虑当前数字,避免多次使用
                    path.pop()
                else: 
                    break

        dfs(0, target, list())
        return res

candidates, target = [10,1,2,7,6,1,5], 8
solu = Solution()
solu.combinationSum2(candidates, target)
[[1, 1, 6], [1, 2, 5], [1, 7], [2, 6]]
# 使用used的写法
class Solution:
    def combinationSum2(self, candidates: list[int], target: int) -> list[list[int]]:
     
        res = list()
        n = len(candidates)
        candidates.sort()
        used = set()
  

        def dfs(idx: int, cur: int, path: list[int]):

            if cur == 0: # 和为target
                res.append(path[:])
                return
            
            for i in range(idx, n):
                # for循环中去重,这里意味着舍弃了i-1所以不能再加入i
                if i > 0 and candidates[i] == candidates[i-1] and i-1 not in used:
                    continue
                if candidates[i] <= cur:
                    path.append(candidates[i])
                    used.add(i)
                    dfs(i+1, cur-candidates[i], path)
                    path.pop()
                    used.remove(i)
                else: 
                    break

        dfs(0, target, list())
        return res

candidates, target = [10,1,2,7,6,1,5], 8
solu = Solution()
solu.combinationSum2(candidates, target)
[[1, 1, 6], [1, 2, 5], [1, 7], [2, 6]]

サブセット

Lituo の質問 78
整数配列 nums が与えられていますが、配列内の要素はそれぞれ異なります。この配列の可能なすべてのサブセット (べき集合) を返します。

ソリューション セットには重複したサブセットを含めることはできません。ソリューション セットは任意の順序で返すことができます。

# 不使用for循环的写法
class Solution:
    def subsets(self, nums: list[int]) -> list[list[int]]:
        res = []
        n = len(nums)

        def dfs(idx: int, path: list[int]):
            if idx == n:
                res.append(path[:])
                return
            path.append(nums[idx])
            dfs(idx+1, path)
            path.pop()
            dfs(idx+1, path)
        
        dfs(0, list())
        return res

nums = [1,2,3]
solu = Solution()
solu.subsets(nums)
[[1, 2, 3], [1, 2], [1, 3], [1], [2, 3], [2], [3], []]
# 使用for循环的写法
class Solution:
    def subsets(self, nums: list[int]) -> list[list[int]]:
        res = []
        n = len(nums)

        def dfs(idx: int, path: list[int]):

            res.append(path[:])
            for i in range(idx, n):
                path.append(nums[i])
                dfs(i+1, path)
                path.pop()
            
        dfs(0, list())
        return res

nums = [1,2,3]
solu = Solution()
solu.subsets(nums)
[[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]]

サブセット II

質問 90 を取得します。
整数の配列 nums が与えられますが、これには繰り返しの要素が含まれる可能性があります。配列の可能なすべてのサブセット (べき集合) を返してください。

ソリューション セットには重複したサブセットを含めることはできません。返されるソリューション セットでは、サブセットは任意の順序で配置できます。

出典: LeetCode
リンク: https://leetcode.cn/problems/subsets-ii
著作権は LeetCode に属します。営利目的での転載の場合は正式な許諾を得た方へ、非営利での転載の場合は出典を明記の上、ご連絡ください。

# 不使用used的写法,依据i > idx来判断
class Solution:
    def subsetsWithDup(self, nums: list[int]) -> list[list[int]]:
        res = []
        n = len(nums)
        nums.sort()

        def dfs(idx: int, path: list[int]):
            res.append(path[:])
            for i in range(idx, n):
                if i > idx and nums[i] == nums[i-1]:
                    continue
                path.append(nums[i])
                dfs(i+1, path)
                path.pop()
            
        dfs(0, list())
        return res

nums = [1,2,2]
solu = Solution()
solu.subsetsWithDup(nums)
[[], [1], [1, 2], [1, 2, 2], [2], [2, 2]]

ノートブック - Github

おすすめ

転載: blog.csdn.net/cjw838982809/article/details/131924759