algorithm – 以最佳方式减少序列

我们给出了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);
点赞