左神算法基础class8—题目8数组中部分元素和等于某个值

1.题目:数组中部分元素的和

给你一个数组arr,和一个整数aim。如果可以任意选择arr中的数字,能不能累加得到aim,返回true或者false

2.暴力递归

(1)分析

思路和8-3打印字符串的子序列相同,对于每个元素可以选择要或者不要,不断递归,形成一个巨大的树,叶节点就是所有元素判断后的结果。f()函数第一位表示当前位置是第几个元素,第二个参数表示当前和。f(0,0)表示初始位置和是0还没开始记录,f(2,5)表示当前在第二位置,和是5。
在这里插入图片描述
结束条件是当前位置超出了数组(每个元素都穷举过了结束),中间过程依旧有一个sum来记录当前和。

(2)核心代码

						//当前数 ,当前和,目标 
bool isSum(vector<int> v,int i, int sum, int aim)
{
	if(i == v.size())
	{
		return sum == aim;
	} 
//	if(sum > aim)	return false;
	return isSum(v,i + 1,sum,aim) || isSum(v,i + 1,sum + v[i],aim);
} 

3.动态规划

(1)分析

①是否有后效性
在这里插入图片描述
对于上述两种情况,需要3,2,不要5和不要3,2,要5,传递出f函数都是f(3,5)说明无后效性。
②dp数组
本题给定的数组,目标aim都不变,只有位置i和sum变化,以i,sum为轴建立二维数组dp
在这里插入图片描述
分析:i表示数组中元素的数量 + 1,之所以加一是因为还需要把未开始的(0,0)位置算进去,sum是数组所有元素的和。那么新建的数组dp[i][j]的意思是在第i个位置当前的和是j,整个dp数组包含了所有可能性。对于aim肯定在0 - sum之间,由本题的递归条件,最后的叶子节点就是想要的结果,那么在叶子节点上(最后一列),不在aim的那一列标记为0,表示不符合F,唯独中间的aim列和刚好和为aim表示为1。
再分析任意位置dp[i][j],根据递归条件当前位置依赖于dp[i + 1][j]表示抛弃当前数(j不变)和dp[i][j + v[i]]加上当前数,体现在数组上就是当前行依赖于下面行的两个位置,一个是垂直下方的位置,一个是下方偏移当前数a的位置,两个只要满足一个和为aim就返回1。

下面的目标就是把数组填好,上方位置的依赖于下方的位置,已知最后一行的aim位置为1,其余为0,就可倒推倒数第二行,最后推出0,0位置返回。
在这里插入图片描述

(2)核心代码

int isSum2(vector<int>& v, int sum, int aim)
{																	//把sum缩减为aim长度,相当于减枝 
	vector<vector<int> > dp(v.size() + 1,vector<int>(aim + 1,0));	//初始化长度加一因为包括了0,0位置 
	
	for (int i = 0; i < dp.size(); i++) 
	{
			dp[i][aim] = 1;											//因为依赖垂直的列 aim列值为1,
	}
	for(int i = dp.size() - 2;i >= 0; i--)
		for(int j = aim - 1;j >= 0;j--)
		{
			dp[i][j] = dp[i + 1][j]; 								//依赖垂直的列
			if(j + v[i] <= aim)										//如果另一个偏移的位置不超出数组范围 
				dp[i][j] = dp[i][j] || dp[i + 1][j + v[i]];			//两个位置有一个满足就可以 
		}
	return dp[0][0];
}

4.完整代码

#include<iostream>
#include<vector>
using namespace std;
//递归					//当前数 ,当前和,目标 
bool isSum(vector<int>& v,int i, int sum, int aim)
{
	if(i == v.size())
	{
		return sum == aim;
	} 
//	if(sum > aim)	return false;
	return isSum(v,i + 1,sum,aim) || isSum(v,i + 1,sum + v[i],aim);
} 
//动态规划 
int isSum2(vector<int>& v, int sum, int aim)
{																	//把sum缩减为aim长度,相当于减枝 
	vector<vector<int> > dp(v.size() + 1,vector<int>(aim + 1,0));	//初始化长度加一因为包括了0,0位置 
	
	for (int i = 0; i < dp.size(); i++) 
	{
			dp[i][aim] = 1;											//因为依赖垂直的列 aim列值为1,
	}
	for(int i = dp.size() - 2;i >= 0; i--)
		for(int j = aim - 1;j >= 0;j--)
		{
			dp[i][j] = dp[i + 1][j]; 								//依赖垂直的列
			if(j + v[i] <= aim)										//如果另一个偏移的位置不超出数组范围 
				dp[i][j] = dp[i][j] || dp[i + 1][j + v[i]];			//两个位置有一个满足就可以 
		}
	return dp[0][0];
}


int main()
{
	vector<int>v = {2,1,7,5};
//	vector<int>v = {12,14,33,45,66,45,33,2,5,4};
//	cout<<isSum(v,0,0,13);
	cout<<isSum2(v,0,13);

	return 0;
}
发布了51 篇原创文章 · 获赞 1 · 访问量 1359

猜你喜欢

转载自blog.csdn.net/shi_xiao_xuan/article/details/104835219
今日推荐