我找不到与我正在处理的这个具体问题有关的问题。 所以问题是,要找到具有最大总和的数组中的连续子集,但是子集的第一个整数应该大于其在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)时间。
答案 0 :(得分:3)
仅针对非负数的O(n)解。
假设数组为a[0], a[1] ... a[n -1]
,其中a[i] >= 0
为0 <= 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.