将数组拆分为两个子阵列,绝对差异最小

时间:2015-01-21 21:07:31

标签: ruby algorithm

例如,考虑数组A:

[3, 1, 2, 4, 3]

我可以在四个地方拆分这个数组:

    P = 1, difference = |3 − 10| = 7
    P = 2, difference = |4 − 9| = 5
    P = 3, difference = |6 − 7| = 1
    P = 4, difference = |10 − 3| = 7

最小差异为1。

数组的每个元素都是[-1,000..1,000]范围内的整数。

以下是我写的代码。我的代码对于本练习是正确的,对于给定的输入是正确的,但在其他一些情况下是不正确的。我不明白为什么。

def minimaldifference(a)
    sumArr = []
    sumArr = sumfromstarting(a)
    sum  = sumArr.last 
    sumRev = sumFromReverse(a, sum)

    size  = sumArr.size-2
    min = 0
    v = 0
    for i in 0..size
        if(i==0)
            min = (sumArr[i] - sumRev[i]).abs
        else
            v = (sumArr[i] - sumRev[i]).abs
            if( v < min)
                min = v
            end
        end
    end
    min
end

def sumfromstarting(a)
    sumArr = []
    sum = 0
    a.each do |i|
        sum += i
        sumArr.push(sum)
    end
    sumArr
end

def sumFromReverse(a, sum)
    sumArr = []
    rsum = 0
    a.each do |i|
        rsum += i
        sumArr.push(sum - i)
    end
    sumArr
end
a = [3, 1, 2, 4, 3]
puts minimaldifference(a)

1 个答案:

答案 0 :(得分:0)

此解决方案要求数组的所有元素都是非负数,我理解是这种情况。

考虑

a = [4,1,3,1,2,4,3,1,5]

此阵列的可能分区如下:

      Partition                 Totals          Diff  Abs Diff
[4], [1,3,1,2,4,3,1,5]                [4,  20]  
[4,1], [3,1,2,4,3,1,5]  [4+1, 20-1] =>[5,  19]   -14     14
[4,1,3], [1,2,4,3,1,5]  [5+3, 19-3] =>[8,  16]    -8      8 
[4,1,3,1], [2,4,3,1,5]  [8+1, 16-1] =>[9,  15]    -6      6
[4,1,3,1,2], [4,3,1,5]  [9+2, 15-2] =>[11, 13]    -2      2
[4,1,3,1,2,4], [3,1,5]  [11+4, 13-4]=>[15,  9]     6      6 
[4,1,3,1,2,4,3], [1,5]  [15+3, 9-3] =>[18,  6]    12     12 
[4,1,3,1,2,4,3,1], [5]  [18+1, 6-1] =>[19,  5]    14     14

在此表的每一行&#34; Diff&#34;等于两组总数之间的差异。因为a的所有元素都是非负的,所以这些值是单调不递减的。因此绝对差异不增加然后不减少。因此,为了获得总数的最小绝对差值,我们简单地逐步通过这个数组,当绝对差值增加时,如果下一个元素从&#34;右边&#34;数组到&#34;左&#34;阵列。

我们可以在代码中实现如下。

def minimize_difference(arr)
  raise ArgumentError, "array must contain at least two elements" if arr.size < 2 
  left, *right = arr
  last = left - right.reduce(:+)
  left = [left]
  while right.any?
    test = last + 2*right.first
    break if test.abs > last.abs
    last = test
    left << right.shift
  end
  [left, right, last.abs]
end  

minimize_difference [3, 1, 2, 4, 3]
  #=> [[3, 1, 2], [4, 3], 1]