最大双切片总和

时间:2013-12-18 14:37:03

标签: java algorithm

最近,我试图解决cod cod中的Max Double Slice Sum问题,这是max slice问题的变体。我的解决方案是在取出最小值时查找具有最大值的切片。所以我实现了最大切片,但是在当前切片上取出了最小数量。

我的得分为61分,因为它在一些测试中失败,主要是阵列上的测试,包括负数和位置数。

您能否帮我弄清楚代码失败的原因或是否有更好的解决方案?

问题如下:

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:
class Solution { public int solution(int[] A); }
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–2013 by Codility Limited. All Rights Reserved. Unauthorized copying, publication or disclosure prohibited.

我的代码如下:

public class Solution {
    public int solution(int[] A) {
        int currentSliceTotal=0; 
        Integer currentMin=null, SliceTotalBeforeMin =0;
        int maxSliceTotal= Integer.MIN_VALUE;
        for(int i= 1; i<A.length-1; i++){
            if( currentMin==null || A[i] < currentMin ){
                if(currentMin!=null ){
                    if(SliceTotalBeforeMin+currentMin <0){
                        currentSliceTotal-=SliceTotalBeforeMin;
                    } else {
                        currentSliceTotal += currentMin;
                    }
                }                
                currentMin = A[i];
                SliceTotalBeforeMin  =currentSliceTotal;

                if( SliceTotalBeforeMin<0){
                    SliceTotalBeforeMin = 0;
                    currentMin = null;
                    currentSliceTotal = 0;
                }
            } else {
                currentSliceTotal+= A[i];
            }

            maxSliceTotal = Math.max(maxSliceTotal, currentSliceTotal);
        }

        return maxSliceTotal;
    }
}

14 个答案:

答案 0 :(得分:20)

如果我已正确理解问题,您需要计算缺少一个元素的最大总和子数组。

您的算法不适用于以下情况:

 1 1 0 10 -100 10 0

在上述情况下,您的算法应将1, 1, 0, 10标识为最大和子数组,并省略0以将12作为输出。但是,您可以在省略1, 1, 0, 10, -100, 10之后将-100作为答案。

您可以使用修改后的Kadane算法形式,计算每个索引结束的MAX Sum子阵列。

  1. 对于每个索引,通过在正向使用Kadane算法计算max_sum_ending_at[i]值。
  2. 对于每个索引,通过反向使用Kadane算法计算max_sum_starting_from[i]值。
  3. 同时迭代这些数组并选择最大值为

    的“Y”

    max_sum_ending_at [Y-1] + max_sum_starting_from [Y + 1]

答案 1 :(得分:6)

你好这个implementacion有100分

int i,n ;

n = A.size();

if (3==n) return 0;

vector<int>  max_sum_end(n,0);
vector<int>  max_sum_start(n,0);

for (i=1; i< (n-1); i++) // i=0 and i=n-1 are not used because x=0,z=n-1
{
  max_sum_end[i]   = max ( 0 , max_sum_end[i-1] + A[i]  ); 
}

for (i=n-2; i > 0; i--) // i=0 and i=n-1 are not used because x=0,z=n-1
{
   max_sum_start[i]   = max ( 0 , max_sum_start[i+1] + A[i]  ); 
}  

int maxvalue,temp;
maxvalue = 0;

for (i=1; i< (n-1); i++)
{
 temp = max_sum_end[i-1]  + max_sum_start[i+1];
 if ( temp >  maxvalue) maxvalue=temp;
}

return maxvalue ;

答案 2 :(得分:3)

这是一个Java 100/100解决方案: 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;

    }
}

您可以在Wikipedia linkProgramming Pearls book中找到更多信息。

答案 3 :(得分:1)

C#解决方案100/100

public int solution(int[] A) {
        int[] forw = new int[A.Length];
        int[] rewi = new int[A.Length];

        bool isAllNeg = true;
        for (int i = 1; i < A.Length; i++)
        {
            forw[i] = Math.Max(0, forw[i - 1] + A[i]);
            if (A[i] > 0 && isAllNeg) isAllNeg = false;

        }

        if (isAllNeg)
            return 0;

        for (int i = A.Length - 2; i >= 0; i--)
        {
            rewi[i] = Math.Max(0, rewi[i + 1] + A[i]);
        }

        int maxsum = 0;
        for (int i = 1; i < A.Length - 1; i++)
        {
            maxsum = Math.Max(maxsum, forw[i - 1] + rewi[i + 1]);
        }

        return maxsum;
}

答案 4 :(得分:1)

不使用额外内存,100/100 C ++:

#include <algorithm>

int solution(vector<int> &A) {
    int max_slice = 0;
    int max_slice_i = 0;

    int min_val = 0;

    int mss = 0;
    int mse = 0;

    int s = 1;

    int msmv = 0;

    int max_slice_i_orig = 0;
    int os = 1;

    for(size_t i = 1;i < A.size() - 1;i++)
    {
        int v = max_slice_i;

        if(max_slice_i > 0 && A[i] < 0)
        {
            if(A[i] < min_val)
            {
                v = max_slice_i_orig;
                s = os;
                min_val = std::max(A[i], -max_slice_i_orig); 
            } else
            {
                v = max_slice_i + A[i];               
            }                        
        } else
        {
            v = max_slice_i + A[i];
        }

        int new_orig_v = max_slice_i_orig + A[i];
        if(new_orig_v < 0)
        {
            max_slice_i_orig = 0;
            os = i + 1;
        } else
        {
            max_slice_i_orig = new_orig_v;
        }

        if(v > 0)
        {                    
            max_slice_i = v;                                   
        } else {            
            max_slice_i = 0;
            min_val = 0;
            s = i + 1;
        }

        if(max_slice_i > max_slice)        
        {
            mss = s;
            mse = i;
            msmv = min_val;
            max_slice = max_slice_i;
        }
    }

    // if all are positive
    if(msmv == 0)
    {
        if(mss == 1 && mse == A.size() - 2)
        {
            int min = 10001;
            for(int j = mss;j <= mse;j++)
            {
                if(A[j] < min)
                    min = A[j];
            }

            max_slice -= min;
        }
    }

    return max_slice;
}

答案 5 :(得分:0)

使用http://en.wikipedia.org/wiki/Maximum_subarray_problem中的想法 和Abhishek Bansal的回答如上。 100%测试通过:

public class Solution {

public int solution(int[] A) {
    int[] maxEndingHere = maxEndingHere(A);
    int[] maxStartingHere = maxStartingHere(A);
    int maxSlice = 0;
    for (int i = 1; i < A.length-1;i++) {
      maxSlice = Math.max(maxSlice, maxEndingHere[i-1]+maxStartingHere[i+1]);
    }
    return maxSlice;
}


/**
 * Precalculate ending subarrays. Take into account that first and last element are always 0
 * @param input
 * @return
 */
public static int[] maxEndingHere(int[] input) {
    int[] result = new int[input.length];
    result[0] = result[input.length-1] = 0;
    for (int i = 1; i < input.length-1; i++) {
        result[i] = Math.max(0, result[i-1] + input[i]);
    }
    return result;
}

/**
 * Precalculate starting subarrays. Take into account that first and last element are always 0
 * @param input
 * @return
 */
public static int[] maxStartingHere(int[] input) {
    int[] result = new int[input.length];
    result[0] = result[input.length-1] = 0;
    for (int i = input.length-2; i >= 1; i--) {
        result[i] = Math.max(0, result[i+1] + input[i]);
    }
    return result;
}

}

答案 6 :(得分:0)

以上解决方案的Vb.net版本如下:

Private Function solution(A As Integer()) As Integer
    ' write your code in VB.NET 4.0
    Dim Slice1() As Integer = Ending(A)
        Dim slice2() As Integer = Starting(A)
        Dim maxSUM As Integer = 0
        For i As Integer = 1 To A.Length - 2
            maxSUM = Math.Max(maxSUM, Slice1(i - 1) + slice2(i + 1))
        Next
        Return maxSUM
End Function
    Public Shared Function Ending(input() As Integer) As Integer()
        Dim result As Integer() = New Integer(input.Length - 1) {}
        result(0) = InlineAssignHelper(result(input.Length - 1), 0)
        For i As Integer = 1 To input.Length - 2
            result(i) = Math.Max(0, result(i - 1) + input(i))
        Next
        Return result
    End Function
    Public Shared Function Starting(input() As Integer) As Integer()
        Dim result As Integer() = New Integer(input.Length - 1) {}
        result(0) = InlineAssignHelper(result(input.Length - 1), 0)
        For i As Integer = input.Length - 2 To 1 Step -1
            result(i) = Math.Max(0, result(i + 1) + input(i))
        Next
        Return result
    End Function
        Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
            target = value
            Return value
        End Function

View result on codility

答案 7 :(得分:0)

基于Abhishek Bansal解决方案的Javascript实现.100 / 100 on Codility。

function solution(A) {

  let maxsum=0;
  let max_end_at=Array(A.length);
  let max_start_at=Array(A.length);
  max_end_at[0]=max_start_at[A.length-1]=max_end_at[A.length-1]=max_start_at[0]=0;
  let {max}=Math;
  for(let i=1;i<A.length-1;i++){

  max_end_at[i]=max(0,max_end_at[i-1]+A[i]);
   }

  for(let n=A.length-2;n>0;n--){

  max_start_at[n]=max(0,max_start_at[n+1]+A[n]);
   }

  for(let m=1;m<A.length-1;m++){

    maxsum=max(maxsum,max_end_at[m-1]+max_start_at[m+1]);

    }
return maxsum;
}

答案 8 :(得分:0)

嗯,我有我的解决方案,可能不是最好的一点100%/ 100%,根据贪婪的要求。

#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;
}

答案 9 :(得分:0)

以下是我之前提出的替代解决方案,更具可读性和可理解性:

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;

}

答案 10 :(得分:0)

这里是python中的100%, 可能不如上面的其他解决方案那么优雅,但会考虑所有可能的情况。

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

答案 11 :(得分:0)

最清晰的Python解决方案:

def solution(A):
    mid = 1
    total = 0
    max_slice = 0

    for idx, end in enumerate(A[2:-1], start=2):

        if total < 0:
            mid = idx
            total = 0

        elif total == 0 and A[idx - 1] > A[mid]:
            mid = idx - 1
            total = end

        else:
            if A[mid] > end:
                total += A[mid]
                mid = idx
            else:
                total += end

        max_slice = max(max_slice, total)

    return max_slice

答案 12 :(得分:0)

认为我是基于Moxis解决方案得到的。试图指出意图。

    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;

}

}

答案 13 :(得分:0)

  

这是我的解决方案   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