利用递归方法求解LeetCode热题100第39题------组合总和

LeetCode 热题 100

39. 组合总和

难度:中等

问题描述:

给你一个无重复元素的整数数组candidates和一个目标整数target,找出candidates中可以使数字和为目标数target的所有不同组合,并以列表形式返回。你可以按任意顺序返回这些组合。

candidates中的同一个数字可以无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。 

对于给定的输入,保证和为target的不同组合数少于150个。

示例 1:

输入:candidates = [2,3,6,7], target = 7

输出:[[2,2,3],[7]]

解释:

2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。

7 也是一个候选, 7 = 7 。

仅有这两种组合。

示例 2:

输入: candidates = [2,3,5], target = 8输出: [[2,2,2,2],[2,3,3],[3,5]]

示例 3:

输入: candidates = [2], target = 1输出: []

力扣系统将这个题归入回溯算法,难度中等,其实很不好做。我用了几天才完成这个题,写一会程序,调试一会,再写再调试,不断修改,不如意处就另辟蹊径,重头再来,最后的结果让人很欣慰,完全通过测试。回想解决这个问题的过程,感觉很困难,甚至想放弃,但自己还是坚持下来,当然成功解决之后的那种喜悦和激动是难以忘怀的。

本次也没有先看别人的解法,而是尝试独自去思考分析,一定要找到自己认为满意或者思维独特的方法,在编写调试过程中,加深了对知识的理解,编程水平无形中又得到提高。路漫漫其修远兮,吾将上下而求索!

程序如下:

#输入candidates和target原始数据
candidates=eval(input('pls input cand='))
target=int(input('pls input target='))

#将比target小的整数选出并按由小到大排序重新组成列表a,因为只有比target小的整数之和才有可能等于target
a=[]
for i in candidates:
    if i<=target:
        a.append(i)
a.sort()
#print('生成的比target小的整数列表a=',a)

#将a中和小于等target的数字组合选取出来并存于b列表中
b=[]
for i in range(len(a)):
    s=a[i]    
    b.append((a[i],))
    #如果取出的这个数刚好是列表中最后一个数,就退出循环
    if i==len(a)-1:
        break
    for j in range(i+1,len(a)):
        s=s+a[j]
        if s<=target:
            b.append(tuple(a[i:j+1]))
        else:
            break
#print('可能的组合:',b)

#check函数用于检验两个整数x和y是否可以经过组合成为target,
#并把组合结果以列表形式返回,结果有可能是一个空列表
def check(x,y,target):
    temp=[]
    m,n=divmod(target,x)
    for i in range(m):
        if (target-(i+1)*x)%y==0:
            temp.append([x]*(i+1)+[y]*((target-(i+1)*x)//y))
    return temp


def check1(target,*nums):
    n=len(nums)
    if n==1:
        a,b=divmod(target,nums[0])
        if b==0:
            return([[nums[0]]*a])
        else:
            return []
    elif n==2:
        return check(nums[0],nums[1],target)
    else:
        x,y=divmod(target,nums[-1])
        temp=[]
        for i in range(x):
            nnums=nums[:len(nums)-1]
            k=check1(target-(i+1)*nums[-1],*nnums)
            for j in k:
                temp.append((i+1)*[nums[-1]]+j)            
        return temp
    
#将b中所有的组合输入得到各种可能的结果存于s中
s=[]
for i in b:    
    r=check1(target,*i)
    if len(r)!=0:
        s=s+r

#清除s中的多余项,结果存于b中
b=[]
for i in s:
    if i in b:
        continue
    else:
        b.append(i)

print('最终结果:\n',b)
        

运行情况

实例1:

pls input candidates=[2,3,4,7,8]

pls input target=13

最终结果:

 [[2, 2, 3, 3, 3], [2, 2, 2, 2, 2, 3], [4, 2, 2, 2, 3], [4, 4, 2, 3], [3, 3, 3, 4]]

实例2

pls input candidates=[5,7,2,8,3,9]

pls input target=20

最终结果:

 [[2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 3, 3, 3, 3, 3, 3], [2, 2, 2, 2, 3, 3, 3, 3], [2, 2, 2, 2, 2, 2, 2, 3, 3], [5, 2, 2, 2, 3, 3, 3], [5, 2, 2, 2, 2, 2, 2, 3], [5, 5, 2, 2, 3, 3], [5, 5, 2, 2, 2, 2, 2], [5, 5, 5, 2, 3], [7, 5, 2, 3, 3], [7, 5, 2, 2, 2, 2], [3, 3, 3, 3, 3, 5], [7, 3, 5, 5], [7, 7, 3, 3], [5, 5, 5, 5], [8, 5, 7]]

总结:生成target的数字组合到底是几个数,可以是一个数、两个数、三个四个或者五个,而且其中的某一个数还有可能被使用多次,具有很大的不确定性,所以如何找出有那些可能生成target的数字组合,这是一个难点,正是因为数字组合数量多少的不确定性,给我们带来了处理的难度,本解法巧妙地使用函数调用可以不确定参数数量的特点,利用递归的方法将复杂问题化为简单问题,从而使问题得到解决。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值