待字闺中之正数数组内和为指定数字的总数

求正数数组内和为指定数字的合并总数

比如[5, 5, 10, 2, 3] 合并值为 15 : 有4种 : (5 + 10, 5 + 10, 5 + 5 + 2 + 3, 10 + 2 + 3)

分析:有的时候,一个题目不能够立刻想到比较优化的想法,就可以先找到一个解决方案,然后根据方案的不足进行优化。而且这个时候,逆转一下思路,便会柳暗花明。由递归到动态规划,不就是如此么?

我们设定f(index,sum)表示数组从index开始到结束组成的sum的总数。那么,f(index, sum)可以表示为什么呢? 我们这个题目,就是要最终求得f(0, 15),从头开始分析,最终组成的和为15的可能组合中,可能包含第0个元素,也可能不包含, 原始数组为A:

  • 当包含第0个元素时,剩下的表示为f(1, 15-A[0])
  • 不包含第0个元素时,剩下的表示为f(1, 15)

则,f(0, 15) = f(1, 15) + f(1, 15 - A[0])。依次递归。递归的终止条件是什么呢?对于f(index,sum):

  • 当和小于等于0的时候,f(index,sum) = 0
  • 当和小于sum的时候, f(index, sum) = f(index + 1, num);
  • 当和等于sum的时候,f(index, sum) = 1 + f(index + 1, sum);

但是,上面的条件,并没有使用题目中,数组全是正数,也就是存在负数也可以。如果仅仅是正数,后两个改为:

  • 当和小于sum的时候, f(index, sum) = 0;
  • 当和等于sum的时候,f(index, sum) = 1;

有一个条件,我们没有使用,也意味着提升的空间。

可是,上面的方案,时间复杂度是指数级。怎么做一些改进呢?一般在对一个算法进行优化的时候,有哪些思路呢?尤其是这种时间很恐怖的?我想很多同学都有这个经验,就是空间换时间。

大家可以想象动态规划的思想,大家看如下的状态转移方程:

dp[n][m]=dp[n-1][m]+dp[n-1][m-num[n-1]]

dp[n][m]表示前n个元素组成和为m的情况数。初始化dp[0][0]=1,其他为0。写出状态转移方程,大家也就明白了,为何要求全是正数了吧,直白一些,数组的索引,怎么可能为负呢?在计算的过程中,将和的情况保存下来,用空间换时间,整个算法的时间复杂度为O(n*m),不再是指数级。

具体代码如下:

int totalCountRecusive(vector<int>& data,int index,int sum)
{
	int length = data.size();
	if(sum == 0) return 1;//找到一个结果
	if(index == length)return 0;
	return totalCountRecusive(data,index+1,sum-data[index]) + totalCountRecusive(data,index+1,sum);//递归
}
int totalCountRecusive(vector<int>& data,int sum)//递归方法
{
	return totalCountRecusive(data,0,sum);
}
int totalCountDp(vector<int>& data,int sum)//动态规划方法
{
	int length = data.size();
	if(length <= 0)return 0;
	vector<vector<int> > dp(length+1);
	int i,j;
	for(i = 0;i <= length;i++)
	{
		vector<int> tmp(sum+1,0);<span style="font-family: Verdana, Arial, Tahoma, Helvetica, Georgia, sans-serif, STXihei, 华文黑体, Hei, 'Hiragino Kaku Gothic Pro', SimSun; font-size: 12px;">//初始化</span>
		dp[i] = tmp;
	}
	for(i = 0;i <= length;i++)dp[i][0] = 1;//初始化
	for(i = length-1;i >= 0;i--)
	{
		for(j = sum;j > 0;j --)
		{
			dp[i][j] = dp[i+1][j];
			if(j - data[i] >= 0)dp[i][j] += dp[i+1][j-data[i]];//分开,防止下标为负数
		}
	}
	return dp[0][sum];
}

待字闺中之正数数组内和为指定数字的总数

时间: 2024-08-08 20:50:51

待字闺中之正数数组内和为指定数字的总数的相关文章

如何在有序数组中给出指定数字出现的次数

问题描述:如何在有序数组中给出指定数字出现的次数,例如:数组{1,2,2,2,3,4,5} 数字2的出现次数为3. 最简单的方法是遍历数组,代码如下: #include <stdio.h> //如何在有序数组中给出指定数字出现的次数 int binarysearch(int *a,int n,int x) { int cnt=0; for(int i=0;i<n;i++) { if(a[i]==x) cnt++; } return cnt; } int main() { int a[10

数组的创建/查找数组里面的内容/添加数组中元素/使用指定的字符串把数组链接起来/判断数组内是否有指定的数组元素/四种遍历进行输出数组中的元素有哪些

#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { //创建数组 //1.快速创建数组@[] NSArray*[email protected][@"month",@"tue",@" wed",@"fir"]; //2,创建空的数组 NSArray*arr=[[NSArray a

记一次逻辑代码的实现(数组内数据按照指定时间差进行分组)

业务场景 有如下数据: id intime outtime1190771865,2019-11-26 13:27:26,2019-11-26 13:27:26 1190771865,2019-11-26 13:27:26,2019-11-26 13:27:26 1190771865,2019-11-26 16:42:46,2019-11-26 16:42:46 1190771865,2019-11-26 13:27:26,2019-11-26 13:27:26 1190771865,2019-1

数组内对象根据指定属性排序

参考:https://www.jianshu.com/p/732461f2439a [arr sortUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) { BTItemModel *item1 = (BTItemModel *)obj1; BTItemModel *item2 = (BTItemModel *)obj2; return [item1.rank compare:item2.rank];

一个关于求数组内最大子数组的和的小程序以及一周总结

一个数组内有正数和负数,而且数组是循环的.求数组内最大子数组的和.要求数组是算法空间复杂度为O(1). 思路: 1.求出每个子数组的值,比较大小. 2.定义一个参数,为数组的长度. 3.构造另外的数组,使得是原数组的得到两个集合.比如a={1,2,3,4}.b={1,2,3,4,1,2,3,4}; 4.这样可以满足数组的循环,参数为原数组的长度. 代码如下: package zuida; import java.io.*; import java.util.Scanner; class qiu

Java的数组长度无需编译指定,因为它是对象

大家可以看从Thinking in Java中摘出来的代码理解一下,甚至.多维数组的子数组无须等长 //: MultiDimArray.java// Creating multidimensional arrays.import java.util.*;public class MultiDimArray {static Random rand = new Random();static int pRand(int mod) {return Math.abs(rand.nextInt()) %

C++_第七章函数的基本知识_求阶乘的子函数_ 函数参数类型为数组_ 求数组内所有元素和、部分元素和的方法_实现了先从键盘输入到一个数组中,再用for循环取读出数组中的元素 for循环也可以用break来结束循环的

/* 第七章函数的基本知识 */ /*01)c++对于返回值有一定的限制:可以是常量.变量.指针.结构对象或表达式,但不可以是数组02)c++返回数组的方法:将数组作为结构会对象组成部分来返回03)函数遇到return则结束该函数04)如果一个函数的两房额参数类型相同,则必须分别制定每个参数的类型,而不能像声明常规变量那样,将声明组合在一起05)*/ //本代码注意double类型的写法以及double和int类型数据的转换 1 #include <iostream> 2 3 void che

LeetCode:Contains Duplicate - 判断数组内是否有重复元素

1.题目名称 Contains Duplicate(判断数组内是否有重复元素) 2.题目地址 https://leetcode.com/problems/contains-duplicate/ 3.题目内容 英文:Given an array of integers, find if the array contains any duplicates. Your function should return true if any value appears at least twice in

算法题——数组内有序对的最大距离

题目:给定一个数组A,对于下标i < j,有A[i] < A[j],求j - i 的最大值. 思路:先正序遍历一次,利用一个辅助数组,记录每个元素的左边子数组中最小值的下标:然后倒序遍历,维持两个指针,初始都指向最后一个元素,通过移动两个指针,找出最大距离. 代码: 1 #include <iostream> 2 #include <vector> 3 using namespace std; 4 5 int maxDist(int num[], int n) 6 {