和为N的种数——背包变形

19 篇文章 0 订阅
8 篇文章 0 订阅

问题:

给一正整数数组A,一正整数n,求数组A的元素相加能够得到和为n的种数。

例如:数组为[5, 5, 10, 2, 3] ,n 为 15,那么种数就为4,分别为:5 + 10, 5 + 10,  5 + 5 + 2 + 3, 10 + 2 + 3。


分析:

最直接的方法就是枚举,但这样的时间复杂度太高,太暴力了!


其实,这一问题与01背包问题类似。

用f[i][v]表示前i个数中能得到和为v的种数,那么其状态转移方程为:

f[i][v] = f[i-1][v] + f[i-1][v-A[i]]。


使用01背包的优化方法,可以只使用一维数组,即空间复杂度O(n)。

若数组A的元素个数为m,那么时间复杂度为O(n*m)。

代码实现:

int getCount(const vector<int> &v, int n){
	int sum = accumulate(v.begin(), v.end(), 0);
	if(sum < n) return 0;
	vector<int> count(n + 1, 0);
	count[0] = 1;
	for(int i = 0; i < v.size(); ++i){
		for(int sumi = n; sumi >= v[i]; --sumi)//逆序遍历
				count[sumi] += count[sumi - v[i]];
	}
	return count[n];
}


PS:01背包类问题,一般适合背包容量不太大的情况。在这里就是n不能够太大,当n比较大,数组的元素比较少的情况下,搜索+剪枝 算法会更优。



扩展:

1. 如果数组里面可以为负数呢? 或者说,可以用加法和减法两种运算呢?印象中,这种情况是微软的一道笔试题。

2. 如果要求的是不能重复的种数呢?例如:数组为[5, 5, 10, 2, 3] ,n 为 15。这时,两个5+10=15只能算作一种,这样总的种数为3。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值