求任何双切片的最大和

时间:2018-07-05 10:19:29

标签: java algorithm time-complexity

我正在尝试从Codility解决我已经有解决方案的问题。问题描述如下,

A non-empty array A consisting of N integers is given.

A triplet (X, Y, Z), such that 0 ≤ X < Y < Z < N, is called a double slice.

The sum of double slice (X, Y, Z) is the total of A[X + 1] + A[X + 2] + ... + A[Y − 1] + A[Y + 1] + A[Y + 2] + ... + A[Z − 1].

For example, array A such that:

    A[0] = 3
    A[1] = 2
    A[2] = 6
    A[3] = -1
    A[4] = 4
    A[5] = 5
    A[6] = -1
    A[7] = 2
contains the following example double slices:

double slice (0, 3, 6), sum is 2 + 6 + 4 + 5 = 17,
double slice (0, 3, 7), sum is 2 + 6 + 4 + 5 − 1 = 16,
double slice (3, 4, 5), sum is 0.
The goal is to find the maximal sum of any double slice.

Write a function:

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

that, given a non-empty array A consisting of N integers, returns the maximal sum of any double slice.

For example, given:

    A[0] = 3
    A[1] = 2
    A[2] = 6
    A[3] = -1
    A[4] = 4
    A[5] = 5
    A[6] = -1
    A[7] = 2
the function should return 17, because no double slice of array A has a sum of greater than 17.

Assume that:

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

expected worst-case time complexity is O(N);
expected worst-case space complexity is O(N) (not counting the storage required for input arguments)

下面提供了解决方案

public static int solution(int[] A) {

        int max = 0;

        int N = A.length;

        int[] A1 = new int[N];
        int[] A2 = new int[N];

        for (int i = 1; i < N - 1; i++) {
            A1[i] = Math.max(A1[i - 1] + A[i], 0);
        }

        for (int i = N - 2; i >= 1; i--) {
            A2[i] = Math.max(A2[i + 1] + A[i], 0);
        }

        for (int i = 1; i < N - 1; i++) {
            max = Math.max(max, A1[i - 1] + A2[i + 1]);
        }

        return max;
    }

我了解在最初的两个循环中做了什么,但是意图并不明确。当我接近最后一个for循环时,我的想法变得混乱。有人请简短地向我解释解决方案吗?

1 个答案:

答案 0 :(得分:1)

我将基于here中的代码进行解释,因为它使用了更清晰的变量名。除此之外,它与您的问题基本相同的代码:

class Solution {
    public int solution(int[] A) {        
        int[] maxStartingHere = new int[A.length];
        int[] maxEndingHere = new int[A.length];
        int maxSum = 0, len = A.length;

        for(int i = len - 2; i > 0; --i ) {            
            maxSum = Math.max(0, A[i] + maxSum);
            maxStartingHere[i] = maxSum;
        }
        maxSum = 0;
        for(int i = 1; i < len - 1; ++i ) {            
            maxSum = Math.max(0, A[i] + maxSum);
            maxEndingHere[i] = maxSum;
        }
        int maxDoubleSlice = 0;

        for(int i = 0; i < len - 2; ++i) {
            maxDoubleSlice = Math.max(maxDoubleSlice, maxEndingHere[i] + maxStartingHere[i+2]);
        }

        return maxDoubleSlice;

    }
}

此处的关键是代码不查找最大切片,而仅查找其总和。数组maxStartingHere在索引i上记录,如果您合并从i+1开始的连续项目,则达到的最大总和; maxEndingHere则相反。让我们来看一个例子:

i:             0  1  2  3  4
A:             1 -3  2 -1  ...
maxEndingHere: 0  1  0  2  1

请注意:

  • i=0i中没有元素,因此总和为0。
  • i=2:采用A[0..1]是次优的,因此0的最大值是通过根本不求和来实现的。
  • i=4:另一个负面因素,但2 + -1仍然比0好。我们之所以不考虑1 + -3 + 2 + -1,是因为我们已经知道我们可以到达2左边的最大值是负数。

我希望您看到该数组显示了通过选择不同的X可以实现的目标,但是并未记录X的具体选择-只是记录了其结果。每个i对应于一个YmaxEndingHere[i-1]对应于针对特定X最优选择Y的结果。

因此,我们知道对于特定的X,最优选择ZY的总和。这意味着仅需选择最佳的Y(或更精确地说:最好的Y产生的总和。这就是在第三循环中发生的事情。

要重申:

  • 从特定项目开始,您可以得到的最大收益是什么?那是maxStartingHere
  • 以某项结束时,从任何地方开始可以得到的最大金额是多少?那是maxEndingHere
  • 在特定项目结束/开始时可获得的最大金额是多少?那是maxDoubleSlice