在数组中找到绝对最小值

时间:2019-10-30 09:26:23

标签: java arrays algorithm

给出了一个由N个整数组成的非空数组A。数组A代表磁带上的数字。

任何整数P,例如0

这两部分之间的区别在于:|(A[0] + A[1] + ... + A[P − 1]) − (A[P] + A[P + 1] + ... + A[N − 1])|

换句话说,它是第一部分之和与第二部分之和之间的绝对差。

例如,考虑数组A:

A[0] = 3
A[1] = 1
A[2] = 2
A[3] = 4
A[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

编写函数:

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

在给定N个整数的非空数组A的情况下,返回可以实现的最小差异。

例如,给定:

A[0] = 3
A[1] = 1
A[2] = 2
A[3] = 4
A[4] = 3

该函数应返回1,如上所述。

为以下假设写出有效的算法:

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

对于上述问题,我尝试了以下方法

    int firstSum = 0;
    int secondSum = 0;
    int tot = Integer.MAX_VALUE;
    List<Integer> col = new ArrayList<>();

    int k=0;
    while(m<A.length)
    {

        firstSum = firstSum + A[k]; 
        for(int i=m; i<A.length; i++)
        {
            secondSum = secondSum + A[i];
        }
        k++;
    }


    System.out.println("Min DIfference: " +tot);

由于上述方法工作正常,但其时间复杂度达到O(N*N),这是不可接受的。 请帮忙弄清楚哪种算法适合该问题。

2 个答案:

答案 0 :(得分:2)

以下方法可能有助于提高复杂性:

我将首先对这些元素进行累加,例如上面的示例:

int[] A = {3,1,2,4,3};

for(int i = 1; i< A.length; i++){
    A[i] = A[i-1]+A[i];
}

产生:

[3, 4, 6, 10, 13]

并在第二个循环中,根据总和得出绝对差,该总和位于索引[A.length-1]处,每个子和在每个索引i

|A[i] - (A[A.length-1] + A[i])|

您的方法可能类似于:

public static int solution(int[] A){
    for(int i = 1; i< A.length; i++){
        A[i] = A[i-1]+A[i];
    }
    System.out.println(Arrays.toString(A));
    int min = Integer.MAX_VALUE;
    for(int i = 0; i< A.length-1; i++){
        if(Math.abs(A[i]-A[A.length-1]+A[i]) < min){
            min = Math.abs(A[i]-A[A.length-1]+A[i]);
        }
    }
    return min;
}

您还可以使用内置方法Arrays.parallelPrefix(int[] array, IntBinaryOperator op)来累积数组的元素并摆脱第一个循环。来自javadoc

  

使用提供的函数并行地累积给定数组中的每个元素。例如,如果数组最初保留[2,1,0,3],并且该操作执行加法,则返回时数组将保留[2,3,3,6]。对于大型数组,并行前缀计算通常比顺序循环更有效。

使用Arrays.parallelPrefix

的代码
public static int solution(int[] A){
    Arrays.parallelPrefix(A, Integer::sum);        
    System.out.println(Arrays.toString(A));
    int min = Integer.MAX_VALUE;
    for(int i = 0; i< A.length-1; i++){
        if(Math.abs(A[i]-A[A.length-1]+A[i]) < min){
            min = Math.abs(A[i]-A[A.length-1]+A[i]);
        }
    }
    return min;
}

答案 1 :(得分:1)

使用前缀和的概念可以降低时间复杂度。

使用2个前缀和数组:

1)forward_prefix_sum(数组元素从左到右的总和)

2)Backward_Prefix_sum(数组元素从右到左的总和)。

最后,遍历数组以计算最小差异​​。

answer = min(abs(forward_prefix_sum[i] - backward_prefix_sum[i]))表示(0 <= i

Time complexity: O(n)