我正在尝试通过leetcode解决Maximum Product Subarray问题。
问题描述是:给定一个整数数组,在该数组中找到包含至少一个具有最大乘积的数字的连续子数组。
示例:输入:[2,3,-2,4],输出:6
为解决这个问题,我使用以下逻辑:让f(p,n)输出正确的结果,直到结果为p的数组的索引n。因此重复是:
f(p,n) = p // if(n=a.length)
f(p,n) = max( p, f(p*a[n], n+1), f(a[n], n+1) ) // otherwise
这适用于常规递归(下面的代码)。
private int f(int[] a, int p, int n) {
if(n==a.length)
return p;
else
return max(p, f(a, p*a[n], n+1), f(a, a[n], n+1));
}
但是,我无法将其转换为自上而下的动态编程。我一直使用的将递归程序转换为使用自上而下的DP的方法是:
这是我一直使用的一种通用方法,它已经解决了我已经完成的大多数dp问题,但是不适用于此问题。
使用此方法的(不正确)代码如下所示:
private int f(int[] a, int p, int n, int[] dp) {
if(dp[n]!=0)
return dp[n];
if(n==a.length)
dp[n] = p;
else
dp[n] = max(p, f_m(a, p*a[n], n+1, dp), f_m(a, a[n], n+1, dp));
return dp[n];
}
我从主函数调用函数如下:
// int x = f(a, a[0], 1, dp); - for incorrect top-down dp attempt
// int x = f(a, a[0], 1); - for regular recursion
不起作用的示例是:[3,-1,4]。在这里,它错误地输出3而不是4。
据我了解,问题在于这两个子问题都引用了DP数组的相同n + 1索引,因此仅解决了1个子问题,这导致了错误的答案。
所以我的问题是:
如何将这种重复性转换为自上而下的DP程序?对于这种情况,我可以遵循一种通用方法吗?
答案 0 :(得分:0)
您的dp
状态取决于当前索引n
和当前结果p
。因此,您需要在2D
数组中记住结果,而不是仅对索引使用1D
数组。
private int f(int[] a, int p, int n, int[] dp) {
if(dp[n][p]!=0)
return dp[n][p];
if(n==a.length)
dp[n][p] = p;
else
dp[n][p] = max(p, f_m(a, p*a[n], n+1, dp), f_m(a, a[n], n+1, dp));
return dp[n][p];
}
答案 1 :(得分:0)
您可以按照尝试的方式进行操作,但是,我将为您建议一种解决其o(n)问题的简便方法,甚至不需要存储数组,因此不需要o(1)空间。
让我们保留2个变量的最小值和最大值。它存储了到目前为止的最小和最大乘积,由于-ve数,我们保留min标记,因为两个负数可以乘积为大数。
休息很容易
初始化min = 1和max = 1且ans = 0(因为qs说至少需要一个数字,所以您可以相应地更改此初始化),即第一个元素。
一次开始读取输入的一个元素,说“ a” 遍历数组的长度
{
if(a> 0)
max = a * max; 否则为(a <0) max =(1> min * a)? 1:分钟* a;
min = max * a; 其他 max = 1;
min = 1; ans =(ans> max)吗? ans:最大; //这在其他地方 } 最大循环数结尾处将是答案,很高兴编码:)
min =(1