Recently, I tried to solve the Max Double Slice Sum problem in codility which is a variant of max slice problem. My Solution was to look for a slice that has maximum value w
Here is my solution https://github.com/dinkar1708/coding_interview/blob/master/codility/max_slice_problem_max_double_slice_sum.py
Codility 100% in Python
def solution(A):
"""
Idea is use two temporary array and store sum using Kadane’s algorithm
ending_here_sum[i] - the maximum sum contiguous sub sequence ending at index i
starting_here_sum[i] - the maximum sum contiguous sub sequence starting with index i
Double slice sum should be the maximum sum of ending_here_sum[i-1]+starting_here_sum[i+1]
Reference -
https://rafal.io/posts/codility-max-double-slice-sum.html
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].
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.
"""
ar_len = len(A)
ending_here_sum = [0] * ar_len
starting_here_sum = [0] * ar_len
# the maximum sum contiguous sub sequence ending at index i
for index in range(1, ar_len - 2): # A[X + 1] + A[X + 2] + ... + A[Y - 1]
ending_here_sum[index] = max(ending_here_sum[index - 1] + A[index], 0)
# the maximum sum contiguous sub sequence starting with index i
for index in range(ar_len - 2, 1, -1): # A[Y + 1] + A[Y + 2] + ... + A[Z - 1]
starting_here_sum[index] = max(starting_here_sum[index + 1] + A[index], 0)
# Double slice sum should be the maximum sum of ending_here_sum[i-1]+starting_here_sum[i+1]
max_slice_sum = ending_here_sum[0] + starting_here_sum[2]
for index in range(1, ar_len - 1):
max_slice_sum = max(max_slice_sum, ending_here_sum[index - 1] + starting_here_sum[index + 1])
return max_slice_sum
Well, I have my solution, may be not the best one bit 100%/100%, according to codility requierments.
#include<vector>
#include<unordered_map>
#include<algorithm>
using namespace std;
int solution(vector<int> &A) {
unordered_map<size_t, int> maxSliceLeftToRight;
maxSliceLeftToRight[1] = 0;
unordered_map<size_t, int> maxSliceRightToLeft;
maxSliceRightToLeft[A.size() - 2] = 0;
int sum = 0;
for (size_t i = 2; i < A.size() - 1; i++) {
int tmpSum = max(sum + A[i - 1], 0);
sum = max(A[i - 1], tmpSum);
maxSliceLeftToRight[i] = sum;
}
sum = 0;
for (size_t i = A.size() - 3; i > 0; i--) {
int tmpSum = max(sum + A[i + 1], 0);
sum = max(A[i + 1], tmpSum);
maxSliceRightToLeft[i] = sum;
}
int maxDoubleSliceSum = 0;
for (auto & entry : maxSliceLeftToRight) {
int maxRight = maxSliceRightToLeft[entry.first];
if (entry.second + maxRight > maxDoubleSliceSum)
maxDoubleSliceSum = entry.second + maxRight;
}
return maxDoubleSliceSum;
}
Think I got it based on Moxis Solution. Tried to point out the Intension.
class Solution {
public int solution(int[] A) {
int n = A.length - 1;
// Array with cummulated Sums when the first Subarray ends at Index i
int[] endingAt = new int[A.length];
int helperSum = 0;
// Optimal Subtotal before all possible Values of Y
for(int i = 1; i < n; ++i ) {
helperSum = Math.max(0, A[i] + helperSum);
endingAt[i] = helperSum;
}
// Array with cummulated Sums when the second Subarray starts at Index i
int[] startingAt = new int[A.length];
helperSum = 0;
// Optimal Subtotal behind all possible Values of Y
for(int i = (n - 1); i > 0; --i ) {
helperSum = Math.max(0, A[i] + helperSum);
startingAt[i] = helperSum;
}
//Searching optimal Y
int sum = 0;
for(int i = 0; i < (n - 1); ++i) {
sum = Math.max(sum, endingAt[i] + startingAt[i+2]);
}
return sum;
}
}
Here 100% in python, might not be as elegant as some other solutions above, but considers all possible cases.
def solution(A):
#Trivial cases
if len(A)<=3:
return 0
idx_min=A.index(min(A[1:len(A)-1]))
minval=A[idx_min]
maxval=max(A[1:len(A)-1])
if maxval<0:
return 0
if minval==maxval:
return minval*(len(A)-3)
#Regular max slice if all numbers > 0
if minval>=0:
max_ending=0
max_slice=0
for r in range(1,len(A)-1):
if (r!=idx_min):
max_ending=max(0,A[r]+max_ending)
max_slice = max(max_slice, max_ending)
return max_slice
#Else gets more complicated
else :
#First remove negative numbers at the beginning and at the end
idx_neg=1
while A[idx_neg] <= 0 and idx_neg<len(A) :
A[idx_neg]=0
idx_neg+=1
idx_neg=len(A)-2
#<0 , 0
while A[idx_neg] <= 0 and idx_neg > 0 :
A[idx_neg]=0
idx_neg-=1
#Compute partial positive sum from left
#and store it in Left array
Left=[0]*len(A)
max_left=0
for r in range(1,len(A)-1):
max_left=max(0,A[r]+max_left)
Left[r]=max_left
#Compute partial positive sum from right
#and store it in Right array
max_right=0
Right=[0]*len(A)
for r in range(len(A)-2,0,-1):
max_right=max(0,A[r]+max_right)
Right[r]=max_right
#Compute max of Left[r]+Right[r+2].
#The hole in the middle corresponding
#to Y index of double slice (X, Y, Z)
max_slice=0
for r in range(1,len(A)-3):
max_slice=max(max_slice,Left[r]+Right[r+2])
return max_slice
pass
This is a Java 100/100 Solution: https://codility.com/demo/results/demoVUMMR9-JH3/
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;
}
}
You can find more information going to this Wikipedia link and in the Programming Pearls book.
Here is an alternative solution to the proposed by me before, more readable and understandable:
int solution(vector<int> & A){
if(A.size() < 4 )
return 0;
int maxSum = 0;
int sumLeft = 0;
unordered_map<int, int> leftSums;
leftSums[0] = 0;
for(int i = 2; i < A.size()-1; i++){
sumLeft += A[i-1];
if(sumLeft < 0)
sumLeft = 0;
leftSums[i-1] = sumLeft;
}
int sumRight = 0;
unordered_map<int, int> rightSums;
rightSums[A.size()-1] = sumRight;
for( int i = A.size() - 3; i >= 1; i--){
sumRight += A[i+1];
if(sumRight < 0)
sumRight = 0;
rightSums[i+1] = sumRight;
}
for(long i = 1; i < A.size() - 1; i++){
if(leftSums[i-1] + rightSums[i+1] > maxSum)
maxSum = leftSums[i-1] + rightSums[i+1];
}
return maxSum;
}