最大和增加子序列,改变算法使用memoization

时间:2017-07-01 18:38:46

标签: 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, 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;
}

1 个答案:

答案 0 :(得分:1)

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

为编写此问题的递归解决方案,您不需要将x作为参数传递,因为x是您希望从函数本身获得的结果。相反,您可以构建一个状态如下:

  • 当前索引:这是您在当前步骤中处理的索引。
  • 最后获取的数字:这是您到目前为止在结果子序列中包含的最后一个数字的值。这是为了确保您在以下步骤中选择较大的数字以保持结果后续序列的增加。

所以你的函数定义类似sum(current_index, last_taken_number) = the maximum increasing sum from current_index until the end, given that you have to pick elements greater than last_taken_number to keep it an increasing subsequence,你想要的答案是sum(0, a small value),因为它计算整个序列的结果。 a small value我的意思是小于整个序列中的任何其他值。

可以使用较小的子状态递归计算

sum(current_index, last_taken_number)。首先假设一些简单的案例:

  • N = 0,结果为0,因为您根本没有序列。
  • N = 1,序列只包含一个数字,结果是该数字,如果数字为负数则为0(我认为空子序列为有效子序列,因此不取任何数字是有效答案)。

现在到了棘手的部分,当N&gt; = 2时。

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

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

  • 取第一个号码。假设它的值是X.那么结果是X + sum(1, X)。这意味着解决方案包含X,因为您决定将其包含在序列中,加上sum(1,X)的结果。请注意,由于我们决定采用X,因此我们将MIN_VAL=X称为和,因此我们选择的以下值必须大于X.

这两项决定都是有效的。结果是这两者中的最大值。因此,我们可以推断出一般的复发如下:

sum(current_index, MIN_VAL) = max( sum(current_index + 1, MIN_VAL) // ignore, seq[current_index] + sum(current_index + 1, seq[current_index]) // take )

第二个决定并不总是有效,因此您必须确保当前元素&gt; 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
}