python 对 各种回溯的实现

# 子集和组合一个概念:不可选之前的数字;排列是所有元素都参与,用数组标记哪些数字本次是否用过

# 子集
def ziji(nums):
    res = []
    trace = []
    def traceback(start, trace):
        res.append(trace.copy()) # copy
        for i in range(start, len(nums)):
            trace.append(nums[i])
            traceback(i + 1, trace) # i + 1
            trace.pop()

    traceback(0, trace)
    return res

# 组合:元素无重复不可复选
def zuhe(nums, target):
    res = []
    trace = []
    def traceback(start, trace):
        if len(trace) == target:
            res.append(trace.copy()) # copy
            return
        for i in range(start, len(nums)):
            trace.append(nums[i])
            traceback(i + 1, trace) # i + 1
            trace.pop()

    traceback(0, trace)
    return res
# 排列
def pailie(nums, target):
    # 不能重复数字,顺序不同则不同
    res = []
    trace = []
    used = [0] * len(nums) # 标记数组
    def traceback(trace):
        if len(trace) == target:
            res.append(trace.copy()) # copy
            return
        
        for i in range(len(nums)):
            if used[i]: continue # 重点

            trace.append(nums[i])
            used[i] = 1
            traceback(trace)
            used[i] = 0
            trace.pop()

    traceback(trace)
    return res


nums = [4, 23, 2]

# print("ziji: ", ziji(nums))
# print(zuhe([1, 2, 3, 4], 3))
# print(pailie([1, 2, 3], 2))


# 数组带有重复数字的子集
def ziji2(nums):
    nums.sort()
    res = []
    trace = []
    def traceback(start, trace):
        res.append(trace.copy()) # copy
        for i in range(start, len(nums)):
            # 需要剪枝
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            trace.append(nums[i])
            traceback(i + 1, trace) # i + 1
            trace.pop()

    traceback(0, trace)
    return res
# print(ziji([1,2,3]))
# print(ziji2([1,2,3,2,2]))


def ziji3(nums, target):
    # 带有重复数字的数组,目标和为target的子集
    nums.sort()
    res = []
    trace = []
    def traceback(start, trace):
        if sum(trace) == target:
            res.append(trace.copy())
            return
        # 可以剪枝:如果目前和已经超过 target(前提:整个数组都是正数),没必要再往下了
        for i in range(start, len(nums)):
            # 需要剪枝
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            trace.append(nums[i])
            traceback(i + 1, trace) # i + 1
            trace.pop()

    traceback(0, trace)
    return res
# print(ziji3([1,2,2,3], 4))

# 排列:数组有重复数字,不可复选
def pailie2(nums, target):
    nums.sort()
    res = []
    trace = []
    used = [0] * len(nums) # 标记数组
    def traceback(trace):
        if len(trace) == target:
            res.append(trace.copy()) # copy
            return
        
        for i in range(len(nums)):
            if used[i] or (i > 0 and nums[i] == nums[i - 1]): continue # 重点

            trace.append(nums[i])
            used[i] = 1
            traceback(trace)
            used[i] = 0
            trace.pop()

    traceback(trace)
    return res

# print(pailie2([1,2,2,3], 2))


def ziji4(nums, target):
    # 数组:不重复,可复选,目标和为target的子集
    res = []
    trace = []
    def traceback(trace):
        if sum(trace) > target: # 大于 target 就没必要往下了
            return
        if sum(trace) == target:
            res.append(trace.copy())
            return

        for i in range(len(nums)):
            trace.append(nums[i])
            traceback(trace)
            trace.pop()

    traceback(trace)
    return res

print(ziji4([1,2,3], 4))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值