break algorithm---暴力搜索:回溯(2)


😡😡😡


声明:
算法基于https://labuladong.github.io/
同步git地址:https://github.com/muxintong/break-algorithm/
python语言实现


39.combination-sum
40.combination-sum-ii







😡😡😡



39.combination-sum

39.combination-sum_1

from typing import List


class Solution:
    '''
    【子集/组合(元素无重可复选)】
        1.标准的子集/组合问题是如何保证【不重复使用】元素的?
            backtrack 递归时输入的参数 start:
            这个 i 从 start 开始,那么下一层回溯树就是从 【i+1】 开始,从而保证 nums[start] 这个元素不会被重复使用。
        2.那么反过来,如果我想让每个元素被【重复使用】,我只要把 i + 1 改成 【i】 即可:
            这相当于给之前的回溯树添加了一条树枝,在遍历这棵树的过程中,一个元素可以被无限次使用:
            当然,这样这棵回溯树会永远生长下去,所以我们的递归函数需要设置合适的base case以结束算法,即路径和大于 target 时就没必要再遍历下去了。
    '''
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        res = []
        track = []
        track_sum = 0
        start = 0

        def backtrack(start: int, track_sum: int):
            # base case:递归出口1
            if track_sum == target:
                res.append(track.copy())
                return
            # base case:递归出口2
            if track_sum > target:
                return

            for i in range(start, len(candidates), 1):
                if candidates[i] + track_sum > target:
                    continue
                elif candidates[i] + track_sum <= target:
                    track_sum += candidates[i]
                    track.append(candidates[i])

                # keypoint:若元素可重复使用,则递归调用仍从i开始。
                backtrack(i, track_sum)

                track_sum -= candidates[i]
                track.remove(candidates[i])

        backtrack(start, track_sum)
        return res


def main():
    # Input: candidates = [2,3,6,7], target = 7
    # Output: [[2,2,3],[7]]
    # Explanation:
    # 2 and 3 are candidates, and 2 + 2 + 3 = 7. Note that 2 can be used multiple times.
    # 7 is a candidate, and 7 = 7.
    # These are the only two combinations.
    solution1 = Solution()
    print(solution1.combinationSum(candidates=[2, 3, 6, 7], target=7))

    print('---')

    # Input: candidates = [2,3,5], target = 8
    # Output: [[2,2,2,2],[2,3,3],[3,5]]
    solution2 = Solution()
    print(solution2.combinationSum(candidates = [2,3,5], target = 8))

    print('---')

    # Input: candidates = [2], target = 1
    # Output: []
    solution3 = Solution()
    print(solution3.combinationSum(candidates = [2], target = 1))


if __name__ == '__main__':
    main()

39.combination-sum_2

from typing import List


class Solution:
    '''
    【子集/组合(元素无重可复选)】
        1.标准的子集/组合问题是如何保证【不重复使用】元素的?
            backtrack 递归时输入的参数 start:
            这个 i 从 start 开始,那么下一层回溯树就是从 【i+1】 开始,从而保证 nums[start] 这个元素不会被重复使用。
        2.那么反过来,如果我想让每个元素被【重复使用】,我只要把 i + 1 改成 【i】 即可:
            这相当于给之前的回溯树添加了一条树枝,在遍历这棵树的过程中,一个元素可以被无限次使用:
            当然,这样这棵回溯树会永远生长下去,所以我们的递归函数需要设置合适的base case以结束算法,即路径和大于 target 时就没必要再遍历下去了。
    '''
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        res = []
        track = []
        track_sum = 0
        start = 0

        def backtrack(start: int, track_sum: int):
            # base case:递归出口1
            if track_sum == target:
                res.append(track.copy())
                return
            # base case:递归出口2
            if track_sum > target:
                return

            for i in range(start, len(candidates), 1):
                if candidates[i] + track_sum > target:
                    continue
                elif candidates[i] + track_sum <= target:
                    track_sum += candidates[i]
                    track.append(candidates[i])

                # keypoint:若元素可重复使用,则递归调用仍从i开始。
                backtrack(i, track_sum)

                track_sum -= candidates[i]
                track.remove(candidates[i])

        backtrack(start, track_sum)
        return res


def main():
    # Input: candidates = [2,3,6,7], target = 7
    # Output: [[2,2,3],[7]]
    # Explanation:
    # 2 and 3 are candidates, and 2 + 2 + 3 = 7. Note that 2 can be used multiple times.
    # 7 is a candidate, and 7 = 7.
    # These are the only two combinations.
    solution1 = Solution()
    print(solution1.combinationSum(candidates=[2, 3, 6, 7], target=7))

    print('---')

    # Input: candidates = [2,3,5], target = 8
    # Output: [[2,2,2,2],[2,3,3],[3,5]]
    solution2 = Solution()
    print(solution2.combinationSum(candidates = [2,3,5], target = 8))

    print('---')

    # Input: candidates = [2], target = 1
    # Output: []
    solution3 = Solution()
    print(solution3.combinationSum(candidates = [2], target = 1))


if __name__ == '__main__':
    main()


😡😡😡



40.combination-sum-ii

40.combination-sum-ii(先排序+相同元素仅处理一次:保证去重)

from typing import List


class Solution:
    '''
    (先排序+相同元素仅处理一次:保证去重)
    先对输入列表排序,在回溯算法的递归调用中通过对相同元素只处理一次的方法进行去重
    '''
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        # 最终结果集res:存储各个track
        res = []
        # 路径列表track:存储符合题意的选择i对应的值candidates[i]
        track = []
        track_sum = 0
        # 组合|子集类问题:
        # 使用起始位start保证元素顺序=>从而保证结果子集与元素顺序无关,为组合型问题,而非排列型问题。
        start = 0

        candidates.sort()

        def backtrack(start: int, track_sum: int):
            # 1 递归出口
            if track_sum == target:
                res.append(track.copy())
                return

            for i in range(start, len(candidates), 1):
                if i>start and candidates[i]==candidates[i-1]:
                    continue
                # 2.1 选择判断:是否符合题意
                # 若不符合:
                if candidates[i] + track_sum > target:
                    continue
                # 若符合:
                elif candidates[i] + track_sum <= target:
                    track_sum += candidates[i]
                    track.append(candidates[i])

                # 2.2 递归
                backtrack(i + 1, track_sum)

                # 2.3 递归后撤销符合题意的选择
                track.remove(candidates[i])
                track_sum -= candidates[i]

        backtrack(start, track_sum)
        return res


def main():
    # Input: candidates = [10,1,2,7,6,1,5], target = 8
    # Output:
    # [
    # [1,1,6],
    # [1,2,5],
    # [1,7],
    # [2,6]
    # ]
    solution1 = Solution()
    print(solution1.combinationSum2(candidates=[10, 1, 2, 7, 6, 1, 5], target=8))

    print('---')

    # Input: candidates = [2,5,2,1,2], target = 5
    # Output:
    # [
    # [1,2,2],
    # [5]
    # ]
    solution2 = Solution()
    print(solution2.combinationSum2(candidates=[2, 5, 2, 1, 2], target=5))


if __name__ == '__main__':
    main()

40.combination-sum-ii(对结果集去重)

from typing import List


class Solution:
    '''
    (对结果集去重)
    '''
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        res = []
        track = []
        track_sum = 0
        start = 0

        def backtrack(start: int, track_sum: int):
            # 1.递归出口
            if track_sum == target:
                res.append(track.copy())
                return

                # 2.组合|子集类问题使用起始位start保证元素顺序
            for i in range(start, len(candidates), 1):
                # 2.1 判断选择i是否符合题意
                # 若不符合
                if track_sum + candidates[i] > target:
                    continue
                # 若符合:做选择
                else:
                    track.append(candidates[i])
                    track_sum += candidates[i]
                # 2.2 递归
                backtrack(i + 1, track_sum)
                # 2.3 递归后撤销选择
                track.remove(candidates[i])
                track_sum -= candidates[i]

        backtrack(start, track_sum)
        # 针对res去重
        res = [sorted(i) for i in res]
        res_tup_nodup = list(set([tuple(i) for i in res]))
        res_list_nodup = [list(i) for i in res_tup_nodup]
        return res_list_nodup


def main():
    # Input: candidates = [10,1,2,7,6,1,5], target = 8
    # Output:
    # [
    # [1,1,6],
    # [1,2,5],
    # [1,7],
    # [2,6]
    # ]
    solution1 = Solution()
    print(solution1.combinationSum2(candidates=[10, 1, 2, 7, 6, 1, 5], target=8))

    print('---')

    # Input: candidates = [2,5,2,1,2], target = 5
    # Output:
    # [
    # [1,2,2],
    # [5]
    # ]
    solution2 = Solution()
    print(solution2.combinationSum2(candidates=[2, 5, 2, 1, 2], target=5))


if __name__ == '__main__':
    main()


😡😡😡





😡😡😡





😡😡😡




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

killingwill

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值