考虑下面这样的数组:
{1, 5, 3, 5, 4, 1}
当我们选择子阵列时,我们将其减少到子阵列中的最小数字。例如,子阵列{5, 3, 5}
变为{3, 3, 3}
。现在,子阵列的总和被定义为所得子阵列的总和。例如,{5, 3, 5}
总和为3 + 3 + 3 = 9
。任务是找到可以从任何子阵列中获得的最大可能总和。对于上面的数组,最大的和是12,由子数组{5, 3, 5, 4}
给出。
是否有可能比O(n 2 )及时更好地解决这个问题?
答案 0 :(得分:3)
假设这些数字都是非负数,这不仅仅是“最大化直方图中的矩形区域”问题吗?现在已经成名......
O(n)解决方案是可能的。这个网站:http://blog.csdn.net/arbuckle/article/details/710988有一堆巧妙的解决方案。
详细说明我的想法(可能不正确)将每个数字视为宽度为1的直方图矩形。
通过“最小化”子阵列[i,j]并加起来,你基本上得到直方图中矩形的区域,从i到j。
之前出现在SO:Maximize the rectangular area under Histogram上,您找到了代码和说明,以及指向官方解决方案页面(http://www.informatik.uni-ulm.de/acm/Locals/2003/html/judge.html)的链接。
答案 1 :(得分:0)
我尝试的以下算法将具有最初用于对数组进行排序的算法的顺序。例如,如果初始数组使用二叉树排序进行排序,则最佳情况下为O(n),平均情况为O(n log n)。
算法要点:
数组已排序。存储排序值和相应的旧索引。从相应的旧索引创建二叉搜索树,用于确定它可以前进和后退多远而不会遇到小于当前值的值,这将导致最大可能的子数组。
我将在问题[1,5,3,5,4,1]中用数组解释方法
1 5 3 5 4 1
-------------------------
array indices => 0 1 2 3 4 5
-------------------------
此数组已排序。以升序存储值及其索引,如下所示
1 1 3 4 5 5
-------------------------
original array indices => 0 5 2 4 1 3
(referred as old_index) -------------------------
重要的是要引用价值及其旧指数;像一个关联数组;
很少有条款要明确:
old_index是指元素的对应原始索引(即原始数组中的索引);
例如,对于元素4,old_index为4; current_index是3;
然而,current_index指的是排序数组中元素的索引; current_array_value引用已排序数组中的当前元素值。
pre指的是前身; succ指的是继承人
此外,min和max值可以直接从排序数组的第一个和最后一个元素获得,分别是min_value和max_value;
现在,算法如下,应该对已排序的数组执行。
算法:
从最左边的元素开始。
对于排序数组左侧的每个元素,应用此算法
if(element == min_value){
max_sum = element * array_length;
if(max_sum > current_max)
current_max = max_sum;
push current index into the BST;
}else if(element == max_value){
//here current index is the index in the sorted array
max_sum = element * (array_length - current_index);
if(max_sum > current_max)
current_max = max_sum;
push current index into the BST;
}else {
//pseudo code steps to determine maximum possible sub array with the current element
//pre is inorder predecessor and succ is inorder successor
get the inorder predecessor and successor from the BST;
if(pre == NULL){
max_sum = succ * current_array_value;
if(max_sum > current_max)
current_max = max_sum;
}else if (succ == NULL){
max_sum = (array_length - pre) - 1) * current_array_value;
if(max_sum > current_max)
current_sum = max_sum;
}else {
//find the maximum possible sub array streak from the values
max_sum = [((succ - old_index) - 1) + ((old_index - pre) - 1) + 1] * current_array_value;
if(max_sum > current_max)
current_max = max_sum;
}
}
例如,
原始数组是
1 5 3 5 4 1
-------------------------
array indices => 0 1 2 3 4 5
-------------------------
,排序的数组是
1 1 3 4 5 5
-------------------------
original array indices => 0 5 2 4 1 3
(referred as old_index) -------------------------
在第一个元素之后:
max_sum = 6 [它将减少到1 * 6]
0
在第二个元素之后:
max_sum = 6 [它将减少到1 * 6]
0
\
5
在第三个元素之后:
0
\
5
/
2
inorder遍历导致:0 2 5
应用算法,
max_sum = [((succ - old_index) - 1)+((old_index - pre) - 1)+ 1] * current_array_value;
max_sum = [((5-2)-1)+((2-0)-1)+ 1] * 3 = 12
current_max = 12 [最大可能值]
在第四个元素之后:
0
\
5
/
2
\
4
inorder遍历结果为:0 2 4 5
应用算法,
max_sum = 8 [由于它小于12而被丢弃]
在第五个元素之后:
max_sum = 10 [减少到2 * 5,因为它小于8而被丢弃]
在最后一个元素之后:
max_sum = 5 [减少到1 * 5,因为它小于8而被丢弃]
此算法将具有最初用于对数组进行排序的算法的顺序。例如,如果初始数组使用二进制排序进行排序,则最佳情况下为O(n),平均情况为O(n log n)。
空间复杂度为O(3n)[O(n + n + n),n为排序值,另一个n为旧索引,另一个n为构造BST]。但是,我不确定这一点。任何关于算法的反馈都表示赞赏。