Algorithm 在不同条件下求连续子集的最大和
我找不到与我正在处理的这个具体问题相关的问题。 所以问题是,要在一个数组中找到具有最大和的连续子集,但是子集的第一个整数应该在O(n)时间内大于它的最后一个整数 例如:Algorithm 在不同条件下求连续子集的最大和,algorithm,Algorithm,我找不到与我正在处理的这个具体问题相关的问题。 所以问题是,要在一个数组中找到具有最大和的连续子集,但是子集的第一个整数应该在O(n)时间内大于它的最后一个整数 例如:2412163195202824 输出应为62(195 20 18)。 到目前为止,我已经提出了这个算法: private int biggestSum(int[] arr) { int startingIndex = 0; int endingIndex = 1; in
2412163195202824
输出应为62(195 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;
}
private int biggestSum(int[]arr)
{
int startingIndex=0;
int-endingIndex=1;
int sum_sou_far=arr[0];
int sum_max=arr[0];
整数计数=0;
对于(int i=1;i最大总和)
{
开始指数=i-计数;
endingIndex=i;
sum_max=迄今为止的sum_;
}
如果(迄今为止的总和小于0)
{
迄今为止的总和=0;
计数=0;
}
}
回报总额最大;
}
我能够得到子集的最大和以及子集的起始索引和结束索引。我怎样才能继续?或者我应该采取不同的方法
谢谢
更新:因为有很多人已经看到了这个问题,但还没有解决它,我想知道是否有人可以证明这在O(n)时间内是不可行的,尽管问题明确提到解决方案应该在O(n)时间内 这里是所有数字的O(n log(n))
,包括负数。这是最糟糕的情况,我相信它的平均性能是O(nlog(log(n))
我们需要一个名为best\u start
的辅助数据结构。它将按值排序存储有关间隔可能起点的信息。对于我们需要知道的每个点,(位置、值、运行总数)
其中位置
是它在数组中的位置,值
是那里的值,运行总数
是它在数组中之前的所有元素的总和
这可以保存在红黑树中,这将保证插入、删除和搜索最接近的值
下面是伪代码
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.
仅适用于非负数的O(n)解
假设数组是a[0],a[1]。。。a[n-1]
,其中a[i]>=0
表示0结束
。因此,所有可能的起点上的数字都必须是递增的
同样,所有可能端点上的数字也必须是递增的
然后我们可以使用两个迭代器找到最佳答案。一个迭代器遍历所有可能的起点,另一个迭代器继续遍历,直到满足要求的最后一个可能的终点第一个整数应该大于最后一个整数
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;
}
int最大和(常数向量和arr)
{
int n=阵列大小();
//前缀和
向量和(n+1);
和[0]=0;
for(int i=1;i arr[starts.back()
开始。推回(i);
//可能的终点
向量末端;
结束。推回(n-1);
对于(int i=n-2;i>=0;--i)
if(arr[i]arr[end]&&sum[end+1]-sum[start]>answer)
答案=和[结束+1]-和[开始];
}
返回答案;
}
数组中的所有数字都是正数吗?它们不必是正数,对于集合2 4 12 16 3-19 5 17 18 24,输出应该是35(4 12 16 3)。也许您可以修改Kadane的算法以适合您的情况?我只是猜测一下。我已经考虑过你说的话,但是如果我在每次迭代中添加一行“if(arr[startingIndex]>arr[endingIndex]),那么我的示例中的数字2永远不会大于集合中的任何其他数字,因此输出将仅为2。所以这将是一个不正确的解决方案。@farzadshbfn,答案不能是一个整数,如前所述,它将与要求相矛盾。谢谢你的想法。你能发一些代码或伪代码吗?我不确定我是否理解如何应用它。谢谢,很好的解决方案!谢谢,我希望你能发表你的评论。这将有助于查看实际代码(没有树的代码)。我很困惑,比如说,位置在伪代码中是如何起作用的?位置的唯一作用是被跟踪的,这样你就可以作为最佳候选者的一部分对其进行报告。如何确定序列的开始是否大于其结束?当我们查看运行的下一个最大值的总和时,我们是保证按顺序查看我们面前的元素,其值大于我们的值。更好的是,这是与我们休会的最佳人选。(高于该数据结构的数据具有较高的运行总数,因此不会产生与该数据结构相同的总和。不在该数据结构中的数据比在该数据结构中的数据更差。)