【问题标题】:Kadane's with a twistKadane的扭曲
【发布时间】:2018-07-22 01:30:16
【问题描述】:

问题:
给定两个数组AB,大小均为n,找到使V = sum(A[i:j]) - min(B[i:j]) 的值最大化的区间[i,j] (0 <= i,j <= n-1)

没有数组Btwist,这个问题只是最大子数组和问题,可以在O(N)用Kadane算法解决。现在,我们有第二个数组,我们从范围中选择最小元素,然后从总和中减去它。

Example:  
 A = [-5, 2, 3, 4, 5]  
 B = [-5, 1, 2, 0, -5]  

Solution: 19   
i=1 to j=4  
2+3+4+5 - (-5) = 19  

一个简单的算法是做一个双循环来计算每个(i,j)区间,但是这种天真的方法有O(N^2)时间复杂度。

我一直在尝试找到O(N),或者至少是O(NlogN) 算法,但我还没有实现。

如果有任何想法,我将不胜感激,谢谢!

编辑:解决方案的实现由彼得供参考:

#include<iostream>
#include<vector>
#include<climits>

using namespace std;

int kadane_modified(vector<int>& A, vector<int>& B){
    if(A.empty() || B.empty()) return 0;

    int size = A.size();

    // Backward Kadane's
    vector<int> R(size);
    int max_so_far = INT_MIN, max_starting_here = 0;

    for (int i = size-1; i >= 0; i--)
    {
        max_starting_here = max_starting_here + A[i];
        if (max_so_far < max_starting_here)
            max_so_far = max_starting_here;

        if (max_starting_here < 0)
            max_starting_here = 0;

        R[i] = max_starting_here;
    }

    // Forward Kadane's
    vector<int> F(size);
    max_so_far = INT_MIN; int max_ending_here = 0;

    for (int i = 0; i < size; i++)
    {
        max_ending_here = max_ending_here + A[i];
        if (max_so_far < max_ending_here)
            max_so_far = max_ending_here;

        if (max_ending_here < 0)
            max_ending_here = 0;

        F[i] = max_ending_here;
    }

    // DP that combines previous results
    vector<int> V(size);
    for(int k = 0; k < size; k++){
        if(k < size-1 & k > 0)
            V[k] = A[k] + R[k+1] - B[k] + F[k-1];
        else if(k == 0)
            V[k] = A[k] - B[k] + R[k+1];
        else if(k == size-1)
            V[k] = A[k] - B[k] + F[k-1];
    }

    // The maximum V is our answer
    int solution = INT_MIN;
    for(int i = 0; i < size; i++){
        if(solution < V[i]) solution = V[i];
    }

    return solution;
}

int main()
{
    vector<int> A = {-5, 2, 3, 4, 5};
    vector<int> B = {-5, 1, 2, 0, -5};

    int solution = kadane_modified(A, B);
    cout << solution << endl;

    return 0;
}  

输出:

19

【问题讨论】:

    标签: arrays algorithm data-structures dynamic-programming kadanes-algorithm


    【解决方案1】:

    Kadane 的算法计算 A 在每个位置结束的最大总和(称为 F[i])。

    您还可以在反转数组 A 上运行 Kadane 的算法,以找到从每个位置开始的 A 的最大和(称为 R[i])。

    然后我们可以使用这两个数组来计算最大子数组和 A[i:j]-B[k] 其中 i

    这解决了“找到满足 i

    这种方法的复杂度是 O(n)。

    【讨论】:

    • 非常感谢彼得!我相信除了你所说的之外,我们应该做一个前锋 Kadane's 来找到每个位置的 A 结尾的最大总和(称为 F[i])。我们应该为每个 k 计算的值是 A[k] - B[k] + R[k+1] + F[k-1]。这确实解决了 O(N) 中的问题,我已经编码并且它确实有效。您认为我添加的内容是必要的,还是我过度计算?
    • 我同意,答案有错字,我打算像你一样使用 F 数组
    • 我明白了,再次感谢。如果您可以编辑它,我可以接受作为答案。
    • @CihanCeyhan 供参考,你能发布你的最终解决方案吗?
    • @SamerTufail 现在添加了它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多