【问题标题】:Two largest contiguous subarray两个最大的连续子阵列
【发布时间】:2017-01-01 02:45:04
【问题描述】:

我目前正在做一个类似于最大连续子数组问题的问题。但是,我可以找到最多两个不重叠的连续子数组,而不是只找到一个连续的子数组。

例如对于下面的测试用例,答案是 20,因为我们可以取除 -20 之外的所有值。

5 3 -20 4 8

为此,我实现了以下代码:

long long n, nums[500500], dp[500500][2][3];

long long best(int numsLeft, int beenTaking, int arrLeft) {
    if (arrLeft < 0 || numsLeft < 0) return 0;

    if (dp[numsLeft][beenTaking][arrLeft] != -1)
        return dp[numsLeft][beenTaking][arrLeft];

    if (beenTaking) {
        // continue Taking
        long long c1 = best(numsLeft - 1, beenTaking, arrLeft) + nums[numsLeft];
        // stop Taking
        long long c2 = best(numsLeft - 1, 0, arrLeft);

        return dp[numsLeft][beenTaking][arrLeft] = max(c1, c2);
    } else {
        // continue not Taking
        long long c1 = best(numsLeft - 1, beenTaking, arrLeft);
        // start Taking
        long long c2 = best(numsLeft - 1, 1, arrLeft - 1) + nums[numsLeft];

        return dp[numsLeft][beenTaking][arrLeft] = max(c1,c2);
    }
}

这是函数调用:

cout << best(n - 1, 0, 2) << endl;

在函数调用之前,dp 数组已经被填充了 -1。 nums 数组包含 n 个元素,索引为零。

Ideone.com 链接是这样的:http://ideone.com/P5PB7h

虽然我的代码确实适用于上面显示的示例测试用例,但它对于其他一些测试用例(我不可用)却失败了。是否有任何边缘情况没有被我的代码捕获?我哪里错了?谢谢你的帮助。

我尝试提出一些这样的边缘案例,但无法做到。

【问题讨论】:

  • 抱歉,您必须获得代码失败的测试输入
  • long long n, nums[500500], dp[500500][2][3]; -- 这是 22 MB 的静态存储空间(如果 sizeof(long long) ==8),可能是堆栈空间,具体取决于声明这些空间的位置。考虑使用std::vector
  • 其他一些测试用例失败(我无法使用) -- 在现实世界中,我们有一些测试用例,程序可能会失败。
  • 另外,你写了一个递归解决方案。你怎么知道你是否没有因为递归太深而导致堆栈溢出?
  • @PaulMcKenzie 我刚刚开始使用算法编程,现在只是掌握了窍门。我还试图找出我的程序失败的测试用例。我尝试减少内存限制(这样程序只会在大型测试用例中失败),但即使对于较小的测试用例,它也会给出错误的答案。

标签: c++ arrays algorithm dynamic-programming kadanes-algorithm


【解决方案1】:

问题似乎出在以下几行:

if (beenTaking) {
    // continue Taking
    long long c1 = best(numsLeft - 1, beenTaking, arrLeft) + nums[numsLeft];
    ...
} else {
    ...
}

在不递减 arrLeft 的情况下添加 best(numsLeft - 1, 1, arrLeft) 意味着“最佳”结果来自 nums[] 中的第一个 numsLeft - 1 值发生在 nums[] 的末尾(在索引 numsLeft - 1 处)。这可能不是真的。

因此,当有超过 2 个由负值分隔的正范围时,代码可能会失败。

此外,dp 数组应初始化为明显超出范围的值,例如 LLONG_MIN,而不是 -1,这可能是一个合法的和。

【讨论】:

  • 出于调试的目的,我完全删除了备忘录,并将 arrLeft 更改为 arrLeft - 1,但现在即使是像 5 5 5 -5 5 5 这样的简单情况,我也会得到错误的答案,当我得到 15 时答案应该是 25(原代码给出了正确答案)。
  • 您询问了您错过的边缘情况。这就是我试图回答的问题。我没有说(或还不知道)正确的解决方案应该基于您的代码。但是如果按方向调试,把初始化改成LLONG_MIN,应该是可以找到的。
猜你喜欢
  • 2011-10-23
  • 2016-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-31
  • 1970-01-01
  • 1970-01-01
  • 2017-04-27
相关资源
最近更新 更多