1. 上题目:
Task description
A non-empty zero-indexed 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:
int solution(int A[], int N);
that, given a non-empty zero-indexed 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), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.
Copyright 2009–2015 by Codility Limited. All Rights Reserved. Unauthorized copying, publication or disclosure prohibited.
大体意思很简单,就是求以X为中心的不包含X的左右两段slice的和的最大值。
2.题目分析
这个题目我乍看之下,觉得是一个很动态的问题,有三个变量,一个是中心点X,一个是左边界Y,一个是右边界Z;有了这三个点才能确定出一个确定的double slice。暴力算法的时间复杂度有O(N3). 但是题目要求O(N)。所以肯定存在一种简便算法来完成这个操作,即通过空间来换时间。
我们冷静的分析一下。
首先,这个最大点,肯定是以中间点X为轴左右两段相加和。对于X来说,这个点的max等于左边的max加上右边的max。即我们只要知道,加到X-1处左边能够加到的最大max,和,从右加到X+1处,右边的max,两者相加就为以X点为轴的max。对于其他左sum与右sum来说,必然小于这个max。
那么我们再以O(N)的时间复杂度遍历所有X点,找出最大的即可~
所以现在的问题就变成,找出每一个点X,左侧的连续max slice sum,以及右侧是max slice sum。
这时,我们惊喜的发现,通过递推的算法,我们又可以通过O(N)的时间复杂度完成这个问题~
1.如果我们确定了i点左侧最大sum,那么i+1点最侧最大的sum就是 max((sum[i]+A[i]),0)
2.通过递推,可以用线性时间复杂度完成 foreMax[] 的构建。
3.同理,可以完成postMax[]的构建。
通过这两个数组在每一个节点上的求和,我们便可找到最大的double slice sum的值哦~
时间复杂度为 O(3*N), 空间复杂度为O(2*N);
3.结果:
1 // you can write to stdout for debugging purposes, e.g. 2 // printf("this is a debug message\n"); 3 4 int solution(int A[], int N) { 5 // write your code in C99 6 int foreMax[N]; 7 int postMax[N]; 8 A[0]=0; 9 A[N-1]=0; 10 11 foreMax[0]=0; 12 // foreMax[1]=0; 13 postMax[N-1]=0; 14 int i; 15 for(i=1;i<N;i++) 16 { 17 if(foreMax[i-1]+A[i-1]>0) 18 { 19 foreMax[i]=foreMax[i-1]+A[i-1]; 20 } 21 else 22 { 23 foreMax[i]=0; 24 } 25 } 26 27 for(i=N-2;i>=0;i--) 28 { 29 if((postMax[i+1]+A[i+1])>0) 30 { 31 postMax[i]=postMax[i+1]+A[i+1]; 32 } 33 else 34 { 35 postMax[i]=0; 36 } 37 } 38 int max = 0; 39 40 for(i=1;i<N-1;i++) 41 { 42 if(foreMax[i]+postMax[i]>max) 43 { 44 max = foreMax[i]+postMax[i]; 45 } 46 } 47 return max; 48 }