从数组中找出元素的最低绝对和

时间:2018-07-15 07:05:59

标签: java arrays algorithm time-complexity

我试图从下面提供的Codility中的问题中了解解决方案,

对于来自集合{−1,1}的给定N个整数的数组A和N个整数的序列S,我们如下定义val(A,S):

val(A, S) = |sum{ A[i]*S[i] for i = 0..N−1 }|

(假设零个元素的总和等于零。)

对于给定的数组A,我们正在寻找使val(A,S)最小的序列S。

编写函数:

class Solution { public int solution(int[] A); }

,给定一个由N个整数组成的数组A,从集合{-1的N个整数的所有可能序列S中,根据val(A,S)的所有可能值计算val(A,S)的最小值。 1}。

例如,给定数组:

  A[0] =  1
  A[1] =  5
  A[2] =  2
  A[3] = -2

您的函数应该返回0,因为对于S = [-1,1,-1,1],val(A,S)= 0,这是可能的最小值。

假设:

N is an integer within the range [0..20,000];
each element of array A is an integer within the range [−100..100].
Complexity:

预期的最坏情况下的时间复杂度为O(N * max(abs(A))2); 预期的最坏情况下的空间复杂度为O(N + sum(abs(A)))(不计算输入参数所需的存储空间)。

在过去的几个小时中,我已经尝试了解了解决方案。

public static int solution(int[] A) {

        int N = A.length;

        int sum = 0;
        int max = 0;

        for (int i = 0; i < N; i++) {

            A[i] = Math.abs(A[i]);
            sum += A[i];

            max = Math.max(A[i], max);
        }


        int[] counts = new int[max + 1];

        for (int i = 0; i < N; i++) {
            counts[A[i]] += 1;
        }

        int[] Total = new int[sum + 1];

        Arrays.fill(Total, -1);
        Total[0] = 0;

        // Segment I
        for (int i = 1; i <= max; i++) {

            if (counts[i] > 0) {

                for (int j = 0; j <= sum; j++) {

                    // j th index is zero or positive
                    if (Total[j] >= 0) {
                        Total[j] = counts[i];
                    }
                    // (i-j) th index is positive
                    else if ((j - i) >= 0 && Total[j - i] > 0) {
                        Total[j] = Total[j - i] - 1;
                    }
                }
            }
        }

        int result = sum;

        // Segment II
        for (int i = 0; i < sum / 2 + 1; i++) {

            // i- th index if zero or positive
            // BODMAS_RULE = {Brackets, Orders, Division, Multiplication, Addition, Subtraction}
            if (Total[i] >= 0) {
                result = Math.min(result, sum - 2 * i);
            }
        }

        return result;
    }

如果任何人都可以解释循环的最后两个部分中发生了什么,这将非常有帮助。我想在几行文字中寻找简短的解释。

UPADTE

我想了解为什么我们在第一段的for循环中使用条件。此外,为什么我们要迭代到第二个for循环中的sum / 2 + 1。谢谢。

1 个答案:

答案 0 :(得分:3)

要使用必需属性求和,您可以找到数组A的子集,其总和应尽可能接近总和的一半。

这是一种well-known postcss.config.js,可以通过动态编程方法解决,方法是使用尺寸对应于总和的附加数组(注释数组subset sum problem)。

请注意,该问题的解决方案仅处理正数,因此您必须对其进行修改以使用负数(例如您的示例Total)。

此代码使数组A[3] = -2的长度为total,并保存数组sum+1中每个值的计数。

在第一阶段,代码用所有可能的总和的非负数条目填充总计表。考虑简单的设置值:count counts
第一轮以值3,2,1,0填充条目0,2,4,6。 第二轮将所有非负输入项更改为三位数和
从非负条目(例如(2:3; 3:2))构建链的递减序列。之后,我们得到的数组4--> 4+3 ->4+6的负数项(不可能的总和)为1,11。请注意,这种方法并不存储信息-使用了哪些项目来产生所有可能的总和,因此您必须进行更多修改。