我正在尝试从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循环时,我的想法变得混乱。有人请简短地向我解释解决方案吗?
答案 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=0
:i
中没有元素,因此总和为0。i=2
:采用A[0..1]
是次优的,因此0
的最大值是通过根本不求和来实现的。i=4
:另一个负面因素,但2 + -1
仍然比0
好。我们之所以不考虑1 + -3 + 2 + -1
,是因为我们已经知道我们可以到达2
左边的最大值是负数。我希望您看到该数组显示了通过选择不同的X
可以实现的目标,但是并未记录X
的具体选择-只是记录了其结果。每个i
对应于一个Y
,maxEndingHere[i-1]
对应于针对特定X
最优选择Y
的结果。
因此,我们知道对于特定的X
,最优选择Z
和Y
的总和。这意味着仅需选择最佳的Y
(或更精确地说:最好的Y
产生的总和。这就是在第三循环中发生的事情。
要重申:
maxStartingHere
。maxEndingHere
。maxDoubleSlice
。