找到具有不同条件的连续子​​集的最大总和

时间:2017-02-03 13:39:30

标签: algorithm

我找不到与我正在处理的这个具体问题有关的问题。 所以问题是,要找到具有最大总和的数组中的连续子集,但是子集的第一个整数应该大于其在O(n)时间内的最后一个整数。

例如:2 4 12 16 3 19 5 20 18 24

输出应为62,(19 5 20 18)。 到目前为止,我已经提出了这个算法:

  private int biggestSum(int[] arr)
    {
        int startingIndex = 0;
        int endingIndex = 1;
        int sum_so_far = arr[0];
        int sum_biggest = arr[0];
        int count = 0;
        for (int i = 1; i < arr.Length; i++)
        {
            sum_so_far += arr[i];
            count++;
            if (sum_so_far > sum_biggest)
            {
                startingIndex = i - count;
                endingIndex = i;
                sum_biggest = sum_so_far;
            }
            if (sum_so_far < 0)
            {
                sum_so_far = 0;
                count = 0;
            }

        }
        return sum_biggest;
    }

我能够获得子集的最大总和以及子集的起始索引和结束索引。我怎么能继续?或者我应该采取不同的方法?

感谢。

更新:由于有很多人已经看过问题而没有解决问题,我想知道是否有人能证明这在O(n)时间内是不可行的,尽管问题清楚地提到解决方案应该在O(n)时间。

2 个答案:

答案 0 :(得分:3)

仅针对非负数的O(n)解。

假设数组为a[0], a[1] ... a[n -1],其中a[i] >= 00 <= i < n,最佳答案为子集a[start], a[start + 1], ..., a[end]

我们可以得出结论a[i] < a[start]0 <= i < start,否则i -> end会比start -> end更好。因此,所有可能起点上的数字必须是升序。

同样,所有可能终点的数字也必须提升。

然后我们可以使用两个迭代器找到最佳答案。一个迭代器遍历所有可能的起始点,另一个迭代器继续行进,直到满足要求first integer should be greater than its last integer的最后一个可能的终点。

c ++代码:

int biggest_sum(const vector<int> &arr)
{
    int n = arr.size();
    // prefix sum
    vector<int> sum(n + 1);
    sum[0] = 0;
    for (int i = 1; i <= n; ++i)
        sum[i] = sum[i - 1] + arr[i - 1];
    // possible start points
    vector<int> starts;
    starts.push_back(0);
    for (int i = 1; i < n; ++i)
        if (arr[i] > arr[starts.back()])
            starts.push_back(i);
    // possible end points
    vector<int> ends;
    ends.push_back(n - 1);
    for (int i = n - 2; i >= 0; --i)
        if (arr[i] < arr[ends.back()])
            ends.push_back(i);
    reverse(ends.begin(), ends.end());  
    // two iterators walking
    int answer = 0;
    for (int i = 0, j = 0; i < starts.size(); ++i) {
        while (j + 1 < ends.size() && arr[ends[j + 1]] < arr[starts[i]])
            ++j;
        int start = starts[i], end = ends[j];
        if (start < end && arr[start] > arr[end] && sum[end + 1] - sum[start] > answer)
            answer = sum[end + 1] - sum[start];
    }
    return answer;
}

答案 1 :(得分:0)

以下是O(n log(n))所有数字,包括否定数字。这是最糟糕的情况,我相信它的平均表现是O(n log(log(n)))

我们需要一个名为best_starts的辅助数据结构。它将按值分类存储有关间隔可能起点的信息。对于我们需要知道的每一点(position, value, running_total),其中position是其在数组中的位置,value是其中的值,running_total是所有元素的总和在数组之前。

这可以保存在红黑树中,这将保证O(log(n))插入,删除和搜索最近的值。

现在这里是伪代码。

initialize best_starts to empty
initialize best candidate to an empty interval
running_total := 0
For each entry in the array:
    # Deal with best_starts first.
    If no equal or bigger value in best_starts:
        insert entry into best_starts
    Else:
        find next largest or equal value
        if its running_total > current running_total:
            while running_total of next largest or equal value >:
               remove next largest or equal value
            insert this (position, value, running_total)

    running_total := running_total + value

    # Now see if we have the best
    calculate running_total - running_total of next largest value
    If that difference > best candidate's total:
        record details on our new best candidate
Our best candidate is the final answer.
相关问题