Algorithm 最大和递增子序列,改变算法使用记忆

Algorithm 最大和递增子序列,改变算法使用记忆,algorithm,recursion,memoization,Algorithm,Recursion,Memoization,我有下面的代码,它实现了这个问题的递归解决方案,而不是使用引用变量“x”来存储总体最大值,我如何或者我可以从递归返回结果,这样我就不必使用有助于记忆的“x” // Test Cases: // Input: {1, 101, 2, 3, 100, 4, 5} Output: 106 // Input: {3, 4, 5, 10} Output: 22 int sum(vector<int> seq) { int x = INT32_MIN; helper(seq

我有下面的代码,它实现了这个问题的递归解决方案,而不是使用引用变量“x”来存储总体最大值,我如何或者我可以从递归返回结果,这样我就不必使用有助于记忆的“x”

// Test Cases: 
// Input: {1, 101, 2, 3, 100, 4, 5} Output: 106
// Input:  {3, 4, 5, 10} Output: 22

int sum(vector<int> seq)
{
    int x = INT32_MIN;
    helper(seq, seq.size(), x);
    return x;
}

int helper(vector<int>& seq, int n, int& x)
{
    if (n == 1) return seq[0];

    int maxTillNow = seq[0];
    int res = INT32_MIN;

    for (int i = 1; i < n; ++i)
    {
        res = helper(seq, i, x);
        if (seq[i - 1] < seq[n - 1] &&  res + seq[n - 1] > maxTillNow) maxTillNow = res + seq[n - 1];
    }

    x = max(x, maxTillNow);
    return maxTillNow;
}
//测试用例:
//输入:{1101,2,3100,4,5}输出:106
//输入:{3,4,5,10}输出:22
整数和(向量顺序)
{
int x=int 32_MIN;
助手(seq,seq.size(),x);
返回x;
}
int-helper(向量和序列、int-n、int-x)
{
如果(n==1)返回seq[0];
int maxTillNow=seq[0];
intres=INT32_MIN;
对于(int i=1;imaxTillNow)maxTillNow=res+seq[n-1];
}
x=最大值(x,最大值);
立即返回maxTillNow;
}

首先,我认为这个实现不正确。对于这个输入
{5,1,2,3,4}
它给出14,而正确的结果是10

为了编写这个问题的递归解决方案,您不需要将x作为参数传递,因为x是您期望从函数本身获得的结果。相反,您可以按照以下方式构造状态:

  • 当前索引:这是您在当前步骤中处理的索引
  • Last take number:这是到目前为止结果子序列中包含的最后一个数字的值。这是为了确保在以下步骤中选择较大的数字,以保持结果子序列的增加
因此,您的函数定义类似于
sum(当前索引,上次取数)=从当前索引到结束的最大递增和,因为您必须选择大于上次取数的元素以保持递增的子序列
,其中您想要的答案是
sum(0,一个小值)
因为它计算整个序列的结果。通过
一个小值
我的意思是比整个序列中的任何其他值都小

sum(当前索引、最后获取的编号)
可以使用较小的子状态递归计算。首先假设简单的情况:

  • N=0,结果是0,因为根本没有序列
  • N=1,序列只包含一个数字,如果数字为负,则结果为该数字或0(我将空子序列视为有效子序列,因此不取任何数字是有效答案)
现在进入棘手的部分,当N>=2时

假设N=2。在这种情况下,您有两种选择:

  • 或者忽略第一个数字,那么问题可以减少到N=1版本,其中该数字是序列中的最后一个数字。在这种情况下,结果与
    sum(1,MIN_VAL)
    相同,其中
    current_index=1
    ,因为我们已经处理了index=0并决定忽略它,而MIN_VAL是我们上面提到的小值

  • 拿第一个号码。假设its值为X,则结果为
    X+和(1,X)
    。这意味着解决方案包括X,因为您决定将其包括在序列中,再加上
    sum(1,X)
    的结果。请注意,我们使用
    MIN_VAL=X
    调用sum,因为我们决定取X,所以我们选择的以下值必须大于X

这两项决定都是有效的。结果是这两个值的最大值。因此,我们可以推导出一般的递推公式如下:

sum(当前索引,最小值)=max(
求和(当前索引+1,最小值)//忽略,
seq[当前索引]+和(当前索引+1,seq[当前索引])//取
)

第二个决定并不总是有效的,因此您必须确保当前元素>MIN_VAL才能有效地执行它

这是该想法的伪代码:

sum(current_index, MIN_VAL){
   if(current_index == END_OF_SEQUENCE) return 0
   if( state[current_index,MIN_VAL] was calculated before ) return the perviously calculated result

   decision_1 = sum(current_index + 1, MIN_VAL) // ignore case
   if(sequence[current_index] > MIN_VAL) // decision_2 is valid
       decision_2 = sequence[current_index] + sum(current_index + 1, sequence[current_index]) // take case
   else
       decision_2 = INT_MIN

   result = max(decision_1, decision_2)
   memorize result for the state[current_index, MIN_VAL]
   return result
}

您指出的有趣的测试用例。让我重做一遍,然后回来。您的psuedo代码类似于硬币兑换或类似问题的类似解决方案,这些问题要求您选择一个值,沿着一条路径,并在回溯时彻底搜索剩余的值。它是类似的,只是您不会彻底搜索,因为记忆会切断许多不必要的探索。如果你需要更多的帮助,请告诉我。