有点晚了,但对于那些正在寻找完整解决方案的人来说,下面是我的。首先,我建议其他人阅读此处给出的答案:https ://stackoverflow.com/a/6165124/4636721以了解动态编程、记忆和制表的含义
无论如何,关于我的解决方案,所以基本上我们有给定的方法:
// Not efficient at all
private static double binomial(int N, int k, double p)
{
if (N == 0 && k == 0)
{
return 1.0;
}
else if ((N < 0) || (k < 0))
{
return 0.0;
}
else
{
return (1.0 - p) * binomial(N - 1, k, p) + p * binomial(N - 1, k - 1, p);
}
}
是的,这真的很慢......递归调用的数量有点大(大约〜N ^ 2)
是的,您可以使用基本上就像其他人已经说明的那样基本上缓存先前计算的值的记忆方法。对于某些人来说,记忆意味着保持递归策略并检查我们需要的值是否已计算,如果没有程序必须计算并缓存它,它真的很容易实现:
private static double binomialTopDown(int N, int k, double p)
{
double[][] cache = new double[N + 1][k + 1];
for (int i = 0; i < (N + 1); i++)
{
Arrays.fill(cache[i], Double.NaN);
}
return binomialTopDown(N, k, p, cache);
}
// More efficient
private static double binomialTopDown(int N, int k, double p, double[][] cache)
{
if ((N == 0) && (k == 0))
{
return 1.0;
}
else if ((N < 0) || (k < 0))
{
return 0.0;
}
else if (Double.isNaN(cache[N][k]))
{
cache[N][k] = (1.0 - p) * binomialTopDown(N - 1, k, p, cache) + p * binomialTopDown(N - 1, k - 1, p, cache);
}
return cache[N][k];
}
诀窍实际上是使用自下而上的方法(也称为制表法)以更有效的方式对计算进行排序。这通常是通过使用上述算法的迭代版本来实现的。
// Much more efficient
private static double binomialBottomUp(int N, int k, double p)
{
/*
double[][] cache = new double[N + 1][k + 1];
cache[0][0] = 1.0;
for (int i = 1; i <= N; i++)
{
cache[i][0] = Math.pow(1.0 - p, i);
for (int j = 1; j <= k; j++)
{
cache[i][j] = p * cache[i - 1][j - 1] + (1.0 - p) * cache[i - 1][j];
}
}
return cache[N][k];
*/
// Optimization using less memory, swapping two arrays
double[][] cache = new double[2][k + 1];
double[] previous = cache[0];
double[] current = cache[1];
double[] temp;
previous[0] = 1.0;
for (int i = 1; i <= N; i++)
{
current[0] = Math.pow(1.0 - p, i);
for (int j = 1; j <= k; j++)
{
current[j] = p * previous[j - 1] + (1.0 - p) * previous[j];
}
temp = current;
current = previous;
previous = temp;
}
return previous[k];
}
这是使用自下而上方法的动态编程最有效的方法。
希望这可以帮助。