K个分区子数组之和的最大值

时间:2018-08-06 09:49:49

标签: java algorithm partition

给出一个数组的子数组,它的值是它包含的出现奇数次的元素的最大值。

我想将一个数组划分为K个子数组,以最大化子数组值的总和。

例如如果我们有以下数组
5 6 6 3 9 K = 2

我们可以按以下方式对其进行分区:
(5)+(6,6,3,9)=(5 + 9 => 14)
(5,6)+(6,3,9)=(6 +9 => 15)
(5,6,6)+(3,9)=(5 + 9 => 14)
(5,6,6,3)+(9)=(5 + 9 => 14)

我能够做到粗暴,但是正在寻找一种有效的算法。你能建议点什么

3 个答案:

答案 0 :(得分:2)

实际上,问题似乎是最大K数之和。因此,只需要按降序进行排序并求和第一个K数即可。

答案 1 :(得分:1)

我看到的算法非常简单。您需要在数组中找到K个最大值的位置,然后以这些位置在不同子数组中的方式对数组进行划分,方法是在每个子数组中包含最大值的次数为奇数次。需要专门研究最后一种情况。一种选择是尝试在达到K限制时获得第一个。

因此,对于(6,6,6)和K = 2,算法应为: 找到2个最大元素(如果达到K限制,则取第一个K)。在我们的例子中,它是第一和第二个6。 然后分成子数组(从max到nextMax-1)

(6) + (6,6) => 6

一个非常有趣的情况是(6,7,6,6)并且K = 3 预期结果是

(6) + (7,6) + (6) = 19

我的算法不能解决这种情况

伪代码:

1. indexes = FindKMaxIndexes() // Use selection algorithm https://en.wikipedia.org/wiki/Selection_algorithm, some variation to save indexes instead of elements values
2. reorder indexes from smallest to largest
3. i = 0
4. for each item in sorted indexes array
4.1 create subarray to include item (from i to current index)
4.2 i = current index + 1  

答案 2 :(得分:0)

很显然,我们可以使用O(n^2 * k),因为如果f(i, k)代表A[i]部分最多可以达到k的最大数量,则:

f(i, k) = max(
  // include A[i] in previous part
  g(A[j..i]) + f(j - 1, k - 1),

  // don't include A[i] in previous part
  A[i] + f(i - 1, k - 1)
)
for all k <= j < i
where g(subarray) is the max element
in subarray that appears an odd number
of times

问题是,我们如何才能更有效地选择要测试包括A[i]在内的哪些子阵列。