专栏 | 九章算法
网址 | www.jiuzhang.com
题目描述
给一个nums[]数组,如[1, 2, 4]
将这些数组合使得: 这些数的和是给出的一个target,如使这些数的和等于4
求这样的组合有多少个?
样例
[1, 1, 1, 1]
[1, 1, 2]
[1, 2, 1]
[2, 1, 1]
[2, 2]
[4]
这些组合都可以,他们的和都是4
所以答案是6
算法分析
1.直观的想法就是把所有的组合全都找出来,再计算他们的个数就可以了。那么,怎么找所有的组合呢?首先你有一个nums数组,一个target。首先想,能不能把这个问题分解成子问题?可以。以题目描述为例,需要[1,2,4]组合成4,可以分解为3个子问题:
序列的第一个数为1,让[1,2,4]组合成3
序列的第一个数为2,让[1,2,4]组合成2
序列的第一个数为4,让[1,2,4]组合成0
2.上述的想法用DFS就可以实现,设N为nums数组的长度,M为target,但是复杂度达到了O(N^M),这个复杂度太高了。 换一个角度来想一想,假设dp[i]为让[1,2,4]为i的组合的数目,如果我dp[1],dp[2],dp[3]都已经求出来了,如何去求dp[4]呢?dp[4]可以由哪些子问题得到呢?这个思路和上面的过程是一样的。
序列的第一个数为1,加dp[3]得到
序列的第一个数为2,加dp[2]得到
序列的第一个数为4,加dp[0]得到
3.dp[0] = 1
dp[1] = 第一个数为1,然后加dp[0]得到 = dp[0] = 1
dp[2] = 第一个数为1,然后加dp[1] + 第一个数为2,然后加dp[0] = dp[1] + dp[0] = 2
dp[3] = 第一个数为1,然后加dp[2] + 第一个数为2,然后加dp[1] = dp[2] + dp[1] = 3
dp[4] = 第一个数为1,然后加dp[3] + 第一个数为2,然后加dp[2] + 第一个数为3,然后加dp[1] = dp[3] + dp[2] + dp[1] = 6
4.于是dp方程为dp[i] = dp[i-nums[1]] + dp[i-nums[2]] + ... + dp[i-nums[N]],初始化dp[0] = 1。复杂度O(NM)。
可以发现,第一种思路和第二种思路其实很相近,他们的区别就是,第二种思路对所有的子过程只计算了一遍,第一种思路可能对一个子过程计算很多遍,例:设dfs(i)可以求出目标为i的结果,dfs(4) = dfs(3) + dfs(2) + dfs(0) = dfs(2) + dfs(1) + dfs(2) + dfs(0) 展开到这一步的时候就可以发现dfs(2)已经被计算了2遍了,而在第二种思路中,每个子过程只会被计算一遍,那么,可不可以让第一种想法计算子过程的时候只计算一遍呢?可以,那就是记忆化搜索。
5.因为题目没说数据是否是递增,可以考虑给数组排序,排序过后 一旦遇到 i - nums[j] < 0的,就可以直接退出循环。
参考代码
面试官角度分析
这道题目的是背包问题当中比较难的面试题目,如果会做01背包,能够拓展想到这道题目多重背包怎么样处理n个背包数目,那么这道题目就能够迎刃而解,能够想出O(n*target)时间复杂度的算法那么久可以达到hire
LintCode相关联系题
登陆www.lintcode.com, 搜索 backpack即可。
Backpack-i
Backpack-ii
Backpack-iii
Backpack-v
推荐阅读
- 12 个 tips 教你搞定 onsite!
- 25 个 questions, 教你向面试官提问!
- 10 个 tips 教你搞定电面!
- 北美IT企业fulltime薪资大曝光
- IT 简历模板大放送 | 《如何写好技术简历》讲座精华总结
- 面试遇到做过的题怎么办?
- 冷冻期大揭秘 | Google、FB、Amazon、Linkedin冷冻期
- 面试前如何了解一家IT企业?试试官方技术博客!
- Google晋升机制 | 大公司如何升级打怪, 获得晋升?
欢迎关注我的微信公众号:九章算法(ninechapter)。
精英程序员交流社区,定期发布面试题、面试技巧、求职信息等
