我们给出了n个数字的序列a.序列a的减少被定义为用max(a [i],a [i 1])替换元素a [i]和a [i 1].
每个减少操作的成本定义为max(a [i],a [i 1]).在n-1次减少后,获得长度为1的序列.
现在我们的目标是打印给定序列的最佳减少的成本,使得得到的长度为1的序列具有最小成本.
例如.:
1
2
3
Output :
5
O(N ^ 2)解决方案是微不足道的.有任何想法吗?
EDIT1:
人们在询问我的想法,所以我的想法是成对地遍历序列,并且每对检查成本,最后以最低成本减少对.
1 2 3
2 3 <=== Cost is 2
所以减少上面的序列
2 3
现在再次遍历序列,我们得到3的成本
2 3
3 <=== Cost is 3
所以总成本是2 3 = 5
以上算法为O(N ^ 2).这就是为什么我要求更优化的想法.
最佳答案 O(n)解决方案:
高水平:
基本思想是重复地将任何小于其邻居ns和nl的元素e与其最小邻居ns合并.这产生了最小的成本,因为合并的成本和结果都是max(a [i],a [i 1]),这意味着没有合并可以使元素比当前小,因此e的最便宜的合并是使用ns,并且该合并不能增加任何其他可能的合并的成本.
这可以通过一次通过算法来完成,方法是按降序保持数组中的元素堆栈.我们将当前元素与其邻居(一个是堆栈的顶部)进行比较,并执行适当的合并,直到我们完成.
伪代码:
stack = empty
for pos = 0 to length
// stack.top > arr[pos] is implicitly true because of the previous iteration of the loop
if stack.top > arr[pos] > arr[pos+1]
stack.push(arr[pos])
else if stack.top > arr[pos+1] > arr[pos]
merge(arr[pos], arr[pos+1])
else while arr[pos+1] > stack.top > arr[pos]
merge(arr[pos], stack.pop)
Java代码:
Stack<Integer> stack = new Stack<Integer>();
int cost = 0;
int arr[] = {10,1,2,3,4,5};
for (int pos = 0; pos < arr.length; pos++)
if (pos < arr.length-1 && (stack.empty() || stack.peek() >= arr[pos+1]))
if (arr[pos] > arr[pos+1])
stack.push(arr[pos]);
else
cost += arr[pos+1]; // merge pos and pos+1
else
{
int last = Integer.MAX_VALUE; // required otherwise a merge may be missed
while (!stack.empty() && (pos == arr.length-1 || stack.peek() < arr[pos+1]))
{
last = stack.peek();
cost += stack.pop(); // merge stack.pop() and pos or the last popped item
}
if (last != Integer.MAX_VALUE)
{
int costTemp = Integer.MAX_VALUE;
if (!stack.empty())
costTemp = stack.peek();
if (pos != arr.length-1)
costTemp = Math.min(arr[pos+1], costTemp);
cost += costTemp;
}
}
System.out.println(cost);