【问题标题】:Maximize sum of list with no more than k consecutive elements from input最大化输入中不超过 k 个连续元素的列表总和
【发布时间】:2013-10-12 11:06:25
【问题描述】:

我有一个 N 个数字的数组,我只想从列表中删除那些元素,这些元素在删除后将创建一个新列表,其中没有更多相邻的 K 个数字对彼此。可以使用此限制创建多个列表。所以我只想要那个列表,其中剩余数字的总和是最大的,并且只作为输出打印那个总和。

到目前为止,我提出的算法的时间复杂度为 O(n^2)。是否有可能为这个问题获得更好的算法?

Link to the question.

这是我的尝试:

int main()
{
    //Total Number of elements in the list
    int count = 6;
    //Maximum number of elements that can be together
    int maxTogether = 1;

    //The list of numbers
    int billboards[] = {4, 7, 2, 0, 8, 9};

    int maxSum = 0;
    for(int k = 0; k<=maxTogether ; k++){
        int sum=0;
        int size= k;

        for (int i = 0; i< count; i++) {
            if(size != maxTogether){
                sum += billboards[i];
                size++;
            }else{
                size = 0;
            }
        }
        printf("%i\n", sum);
        if(sum > maxSum)
        {
            maxSum = sum;
        }
    }
    return 0;
}

【问题讨论】:

  • 你能分享你想出的代码吗?
  • 你能举个例子吗?您的问题描述不清楚。
  • 你能不能说的更具体一些并提供一个例子?
  • 如果你看实际的问题,我的回答甚至可能是错误的:(
  • @RBarryYoung 这个重述可能会有所帮助 - “从一个数组中选择任意数量的元素,其中选择的连续元素不超过 k 个。最大化所选择元素的总和。”

标签: algorithm


【解决方案1】:

O(NK)dynamic programming 解决方案相当简单:

A[i] 成为左侧元素的最佳总和,受 not-k-连续约束(假设我们也删除了 i-th 元素)。

然后我们可以通过回顾K元素来计算A[i]

A[i] = 0;
for j = 1 to k
  A[i] = max(A[i], A[i-j])
A[i] += input[i]

最后,只需查看 A 中的最后一个 k 元素,将元素添加到每个元素的右侧并选择最佳元素。

但这太慢了。

让我们做得更好。

所以A[i]A[i-1]A[i-2]、...、A[i-K+1]A[i-K] 中找到最好的。
所以A[i+1]A[i]A[i-1]A[i-2]、...、A[i-K+1] 中找到最好的。

那里有很多冗余 - 由于A[i] 的计算,我们已经从索引i-1i-K 中知道了最好的,但后来我们找到了除i-K 之外的所有这些中最好的(@ 987654347@) 再次进入A[i+1]

所以我们可以将它们全部存储在一个有序的数据结构中,然后删除A[i-K] 并插入A[i]。我的选择 - 一个 binary search tree 来找到最小值,以及一个大小为 K+1 的树节点的 circular array,这样我们就可以轻松找到我们需要删除的那个。

我交换了问题以使其稍微简单一些 - 我没有找到剩余元素的最大值,而是找到已删除元素的最小值,然后返回 total sum - removed sum

高级伪代码:

for each i in input
  add (i + the smallest value in the BST) to the BST
  add the above node to the circular array
    if it wrapper around, remove the overridden element from the BST

// now the remaining nodes in the BST are the last k elements

return (the total sum - the smallest value in the BST)

运行时间:

O(n log k)

Java 代码:

int getBestSum(int[] input, int K)
{
   Node[] array = new Node[K+1];
   TreeSet<Node> nodes = new TreeSet<Node>();
   Node n = new Node(0);
   nodes.add(n);
   array[0] = n;
   int arrPos = 0;
   int sum = 0;
   for (int i: input)
   {
      sum += i;
      Node oldNode = nodes.first();
      Node newNode = new Node(oldNode.value + i);
      arrPos = (arrPos + 1) % array.length;
      if (array[arrPos] != null)
         nodes.remove(array[arrPos]);
      array[arrPos] = newNode;
      nodes.add(newNode);
   }
   return sum - nodes.first().value;
}

getBestSum(new int[]{1,2,3,1,6,10}, 2) 根据需要打印21

【讨论】:

  • 这应该是选择的答案——它正确地提到了 O(nk) 解决方案以及如何将其优化为 o(nlog(k))。谢谢!
【解决方案2】:

f[i] 成为您可以使用前 i 个数字获得的最大总值,而您不要选择最后一个(即第 i 个)。然后我们有

f[i] = max{
           f[i-1],
           max{f[j] + sum(j + 1, i - 1) | (i - j) <= k}
          }

您可以使用类似heap 的数据结构来维护选项并在log(n) 时间内获得最大值,保留全局delta 或其他任何内容,并注意i - j &lt;= k 的范围。

【讨论】:

    【解决方案3】:

    以下算法的复杂度为 O(N*K)。

    检查数组的第一个 K 元素(0 到 K-1)。该区域最多可以有 1 个间隙。
    原因:如果有两个差距,那么就没有任何理由有更低的(早期差距)。

    For each index i of these K gap options, following holds true:  
     1. Sum upto i-1 is the present score of each option.  
     2. If the next gap is after a distance of d, then the options for d are (K - i) to K  
    
    For every possible position of gap, calculate the best sum upto that position among the options.  
    The latter part of the array can be traversed similarly independently from the past gap history.
    

    进一步遍历数组直到结束。

    【讨论】:

    • 我相信 O(NK) 对于这个特定问题来说太慢了(最大 N = 最大 K = 10^5)。
    • 是的,我找不到有效地为给定差距选择最佳总和的方法。
    • @dukeling 这些信息在哪里?我在此页面上的任何地方都找不到它。另外,O(10^5 * 10^5) 真的是 OP 的问题吗?大多数现代计算机可以在一分钟内完成 O(10^10)。
    • @Dukeling 哎呀,好的,我现在看到链接了。我的第二个问题仍然存在..
    • @RBarryYoung The time limit on HackerRank is just a few seconds。诚然,可以通过非常有效的实现(取决于有多少测试用例)。
    猜你喜欢
    • 1970-01-01
    • 2011-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-22
    • 1970-01-01
    相关资源
    最近更新 更多