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的数字组合,这是一个难点,正是因为数字组合数量多少的不确定性,给我们带来了处理的难度,本解法巧妙地使用函数调用可以不确定参数数量的特点,利用递归的方法将复杂问题化为简单问题,从而使问题得到解决。