将整数数组划分为K个组,使每个组的范围最小

时间:2017-04-26 11:54:04

标签: algorithm partitioning

因此,更正式地说,我得到了N个数字,需要将它们分成K组,而这些组中没有这些组是空的。每组中的范围总和需要最小化。例如:

N = 4,K = 2,输入为{5,3,1,1}。

一种可能的解决方案是{5,3},{1,1}。范围之和为2((5-3)+(1-1))。

另一种看待它的方法是{1,1,3} {5},它也是2((3-1)+(单个数字的范围是0))。

范围始终是组中最大数字与组中最小数字之间的差异。

当我搜索互联网时,很明显我需要使用动态编程,但我提出的所有内容都是K = 2的解决方案。

有人可以帮忙吗?

4 个答案:

答案 0 :(得分:2)

  1. 对数组进行排序。
  2. m 成为数组的m th 元素;然后,让 m = a m - a m-1 ∀m∈[1; N)。减法循环必须向后运行以避免更改 m-1 。 a 0 ≡0。
  3. 对结果数组进行排序,保持元素的初始索引按照与元素本身相同的顺序排序。
  4. 取最后的K-1指数:这些指数加上0,是搜索组中第一批元素的指数。

答案 1 :(得分:0)

通过动态编程,你想出了一个k = 2的解决方案。现在想想如何将它扩展到k = 3.

假设f2(n)返回k = 2和前n个数的最优解,f3(n)= f2(n-m)+ err(n-m,n)。这是扩展它的一种方式。

答案 2 :(得分:0)

假设您的数据已经排序,您可以在线性时间内完成。

您可以在min_valuemax_value之间的轴上查看数据。简而言之,聪明的解决方案不使用非连续组,因此任何聪明的解决方案都可以表示为轴上的一组K段,每个段[x1, x2]代表数据中x1之间的所有数字。 1}}和x2

您的解决方案的总费用是所有段长度的总和,也是max_value - min_value - (space between all your segments)。段之间的空间本身由K - 1"空段"组成,即没有输入数字,即两个连续输入数字之间的段。你想要的是最大化K - 1这些段的长度之和。

所以你要做的就是(简单版):

  • 如有必要,请对输入进行排序
  • 计算B [i] = A [i + 1] - 所有i的A [i](A是排序的输入数组)
  • 检索B-K的最大值(仍然是线性时间,实际上可以与上一步同时完成)
  • 这些是您的组的边界,因此您可以再次遍历A以自己创建组(现在您已经拥有边界)(此步骤也可以与之前的组合完成)

如果您的不同值的数量大于K,则必然所有组都将为非空。如果不是,您可以轻松拆分包含相同值的重复项的组,以使所有组都为非空。

复杂性(如果已经排序):O(n * k)(最多)如果K是常数则是O(n)。如果没有,只需改进搜索最佳K-1段以获得最多O(n log(n))

如上所述,额外的存储器复杂性很容易为O(K)

答案 3 :(得分:0)

因此,在这个问题中,我们希望最小化组的范围。

所以我们假设我们有数组A = {1,3,5,7,5,2}

每个数组的最大范围为max[a]-min[a],最小范围0

我们可以使用二进制搜索的变体来找到最小范围,这个答案是关于组必须包含字母数字的约束。

对于二进制搜索,我们需要选择由数组的最小和最大范围给出的边界。

这个psuedo / java代码看起来像这样。

main(){
  int upper = max(A)-min(A); 
  int lower = 0;  


  while (true) {
    int mid =  upper-lower;  
    int blocks = calculateBlockCount(A, mid); 
    if (blocks < K) {
      upper = mid - 1;
    } 
    else if (blocks > K) {
      lower = mid + 1;
    } 
    else {
      return upper;
      break;
    }
  }
 }

    private static int calculateBlockCount(int[] array, int range) {
      int count = 0;
      int[] dumie_array;
      int dumie_array[].add[array[0]];

      for (int i = 0; i < array.length; i++) {
        int dumie_array[].add[array[i]]
         if (Func_range(dumie_array) > range) {
           count++;
           dumie_array = array[i];
         } 
         else {
           dumie_array.add(array[i]);
         }
      }
      return count;
    }

    private static int Func_range(int[] input) {
       int range = 0;
       range= max(input)-min(input)
       return sum;
     }

希望stil帮助

我认为大部分都适用于java,只有C ++所具有的添加功能才存在。 (不想通过制作一个arraylist来写这么多。)但我认为该计划的想法应该是明确的。
这都是基于这篇文章 Need explanation for algorithm searching minimal large sum。 这是一个非常相似的问题。

干杯, 的Gijs