目录
一、回溯法简介
回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。回溯法很有趣可以解决一系列的问题,比如子集问题、排列问题以及八皇后问题等。是个很值得研究和学习的算法。可以细看我之前的博客https://blog.csdn.net/kupepoem/article/details/106662487和https://blog.csdn.net/kupepoem/article/details/106665698
二、动态规划简介
动态规划程序设计是对解最优化问题的一种途径、一种方法,而不是一种特殊算法。不像搜索或数值计算那样,具有一个标准的数学表达式和明确清晰的解题方法。动态规划程序设计往往是针对一种最优化问题,由于各种问题的性质不同,确定最优解的条件也互不相同,因而动态规划的设计方法对不同的问题,有各具特色的解题方法,而不存在一种万能的动态规划算法,可以解决各类最优化问题。因此读者在学习时,除了要对基本概念和方法正确理解外,必须具体问题具体分析处理,以丰富的想象力去建立模型,用创造性的技巧去求解。我们也可以通过对若干有代表性的问题的动态规划算法进行分析、讨论,逐渐学会并掌握这一设计方法。 可以参看我之前的博文。
三、题目
来源:https://leetcode-cn.com/problems/combination-sum-iv
给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数。
示例:
nums = [1, 2, 3]
target = 4
所有可能的组合为:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
请注意,顺序不同的序列被视作不同的组合。
因此输出为 7。
四、实现
1、思路
这和Combination Sum1-3比较类似,沿用Combination Sum即可。沿用Combination Sum思路你会发现计算会超时,因为枝干实在是太多。那么加入dp记录下一些中间结果,进一步的进行剪枝。
2、回溯法递归
下面的回溯法递归代码是会超时的。
int combinationSum_help2(vector<int>& candidates,int resval ,std::vector<int> &dp)
{
if (resval == 0)
{
return 1;//剪枝
}
else if(resval<0)
{
return 0;//剪枝
}
int sumres=0;
for (int i = 0; i < candidates.size(); ++i)
{
sumres+=combinationSum_help2(candidates, resval - candidates[i],dp);
}
dp[resval]=sumres;
return sumres;
}
int combinationSum4(vector<int>& nums, int target)
{
int res=0;
std::vector<int> dp;
dp.resize(target+1);
for(int i=0;i<target+1;i++)
dp[i]=-1;
int sum=combinationSum_help2(nums, target,dp);
return sum;
}
3、回溯法递归+dp
int combinationSum_help2(vector<int>& candidates,int resval ,std::vector<int> &dp)
{
if (resval == 0)
{
return 1;//剪枝
}
else if(resval<0)
{
return 0;//剪枝
}
if(dp[resval]!=-1)
return dp[resval];//剪枝
int sumres=0;
for (int i = 0; i < candidates.size(); ++i)
{
sumres+=combinationSum_help2(candidates, resval - candidates[i],dp);
}
dp[resval]=sumres;
return sumres;
}
int combinationSum4(vector<int>& nums, int target)
{
int res=0;
std::vector<int> dp;
dp.resize(target+1);
for(int i=0;i<target+1;i++)
dp[i]=-1;
int sum=combinationSum_help2(nums, target,dp);
return sum;
}
五、总结
算法设计还是要掌握其中的思想,掌握了思想问题也就迎刃而解了。