查找数组中的绝对最小值

Posted

技术标签:

【中文标题】查找数组中的绝对最小值【英文标题】:Find the absolute minimum in an array 【发布时间】:2019-10-30 09:26:23 【问题描述】:

给定一个由 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),这是不可接受的。 请帮忙看看哪种算法适合这个问题。

【问题讨论】:

为什么有这么多接近投票? @OleV.V.不,绝对不是先生,我尝试了一些算法,但我能得到的最好的只是上面的。 显然您不是在寻求编码方面的帮助。对我来说,这似乎是一个算法和数学的问题。 这不就是个小问题吗? @OleV.V.是的,它也可以包含负值 【参考方案1】:

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

我会首先对元素进行累积总和,即对于您上面的示例,如下所示:

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;

【讨论】:

太棒了,我的脑袋敲了很久,太感谢了。 您愿意分享这背后的思考过程吗?你有没有遵循任何算法?【参考方案2】:

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

使用 2 个前缀和数组:

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

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

最后遍历数组,计算出最小差值。

answer = min(abs(forward_prefix_sum[i] - backward_prefix_sum[i])) for (0

Time complexity: O(n)

【讨论】:

以上是关于查找数组中的绝对最小值的主要内容,如果未能解决你的问题,请参考以下文章

查找数组中的最小值(我的代码有啥问题?)

使用绝对函数查找两个数字的最小值

查找数组中的最小值

在javascript中的数组中查找多个最小值的索引

C语言丨如何查找数组(序列)中的最大值或者最小值?

查找数组中的最大值(最小值)及相对应的下标