Algorithm 硬币兑换算法和伪代码:需要澄清吗
我试图理解硬币兑换问题的解决方案,但遇到了一些困难 在,动态规划解决方案有一个伪代码解决方案,如下所示:Algorithm 硬币兑换算法和伪代码:需要澄清吗,algorithm,dynamic-programming,coin-change,Algorithm,Dynamic Programming,Coin Change,我试图理解硬币兑换问题的解决方案,但遇到了一些困难 在,动态规划解决方案有一个伪代码解决方案,如下所示: n = goal number S = [S1, S2, S3 ... Sm] function sequence(n, m) //initialize base cases for i = 0 to n for j = 0 to m table[i][j] = table[i-S[j]][j] + table[i][j-1] 这是一个非常标准的O(
n = goal number
S = [S1, S2, S3 ... Sm]
function sequence(n, m)
//initialize base cases
for i = 0 to n
for j = 0 to m
table[i][j] = table[i-S[j]][j] + table[i][j-1]
这是一个非常标准的O(n^2)
算法,它避免了使用二维数组多次重新计算相同的答案
我的问题有两个方面:
表[]【】
如果n==0,则返回1
如果n<0,则返回0
如果n>=1&&m我们可以用至少两种不同的方法实现动态规划算法。一种是使用记忆的自顶向下方法,另一种是自底向上迭代方法 对于动态规划的初学者,我总是建议首先使用自上而下的方法,因为这将帮助他们理解动态规划中的循环关系 因此,为了解决硬币兑换问题,您已经了解了循环关系的含义:
这种递推关系很好,但由于没有任何边界条件,因此定义得不太明确。因此,我们需要定义边界条件,以确保递归关系能够在不进入无限循环的情况下成功终止 那么,当我们尝试沿着递归树往下走时会发生什么呢 如果我们需要计算table[i][j] = table[i-S[j]][j] + table[i][j-1]
,这意味着使用表[i][j]
类型的硬币将0
更改为i
类型的方法的数量,我们需要处理以下几种情况: 1) 如果j
j==0怎么办 如果
我们将尝试解决子问题j==0
,该子问题不是有效的子问题。因此,一个边界条件是:表(i,j-1)
2) 如果if(j==0) { if(i==0) table[i][j] = 1; else table[i][j] = 0; }
呢 我们还需要处理这个边界情况,我们知道在这种情况下,我们不应该试图解决这个子问题,也不应该为所有这些情况初始化i-S[j]<0
总之,如果我们要从自上而下的记忆方法实现这种动态编程,我们可以这样做:表(i-S[j],j)=0
实际上,我们也可以使用int f(int i, int j) { if(calc[i][j]) return table[i][j]; calc[i][j] = true; if(j==0) { if(i==0) return table[i][j]=1; else return table[i][j]=0; } if(i>=S[j]) return table[i][j]=table[i-S[j][j]+table[i][j-1]; else return table[i][j]=table[i][j-1]; }
数组的值来帮助跟踪此子问题之前是否已计算过(例如,我们可以初始化值-1表示此子问题尚未计算)表
希望答案是清楚的。:) 谢谢你的澄清。两点:
的确切来源是什么?作为布尔条件,它在哪里设置为false?其次,作为一个二维数组,我将如何提取可能的序列?@Jason:calc
是一个布尔型矩阵,它表示这个“子问题”以前是否计算过,如果计算过,那么我们不需要重新计算,我们只需使用以前的计算结果。这是dynamic的核心programming@Jason:尽管提取可能的序列是一个完全不同的问题,因为可能性的数量可能相当大,但您仍然可以使用向量v[i][j]来跟踪这一点,遵循类似的关系。calc