2013-12-18 44 views
9

最近,我试图解决最大切片问题变种的最大双切片和问题。我的解决方案是在取出最小值时寻找具有最大值的切片。所以我实现了最大切片,但在当前切片中取出了最小数量。最大双切片总和

我的分数是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; 
    } 
} 

回答

16

如果我理解正确的问题,你想用一个元素来计算最大总和子数组失踪。

你的算法,不得用于下列情况下工作:

1 1 0 10 -100 10 0 

在上述情况下,你的算法应确定1, 1, 0, 10作为最大总和子数组,并离开了012作为输出。但是,您可以在退出-100之后将1, 1, 0, 10, -100, 10作为答案。

您可以使用修改后的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]

+0

谢谢阿布舍克。这是一个优雅的解决方案。 –

+0

辉煌的解决方案,阿布舍克。通过查找最大化其左右最大序列之和的索引来搜索“Y”值。 – AndyG

+0

@AndyG谢谢.. :) –

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 ; 
+0

我认为这不起作用,如果数组只有负值。考虑到2个子数组必须至少包含一个元素,您不能只将max_sum设置为cero。 –

+0

这两个子数组可以是0.请参阅问题中的双切片(3,4,5),和为0.。 – ksloan

0

http://en.wikipedia.org/wiki/Maximum_subarray_problem 使用理念及以上阿布舍克邦萨尔的回答。 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; 
} 

}

0

VB。上述解决方案的网络版本如下:

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

2

这是一个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 link和在Programming Pearls book

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

Javascript实现基于阿布舍克邦萨尔的solution.100/100 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; 
} 
1

嗯,我有我的解决方案,可能不是最好的一个工具100%有效,根据codility requierments。

#include <vector> 
#include <algorithm> 
#include <numeric> 
#include <functional> 

typedef unsigned int uint; 


void unifySums(const std::vector<std::pair<std::pair<uint, uint>, std::pair<int, int>>> & sums, 
    const std::vector<std::pair<std::pair<uint, uint>, std::pair<int, int>>> & betweenSums, 
    std::vector<std::pair<std::pair<uint, uint>, std::pair<int, int>>> & unifiedSums, 
    std::vector<std::pair<std::pair<uint, uint>, std::pair<int, int>>> & betweenUnifiedSums 
) 
{ 
    for (uint i = 0; i < betweenSums.size(); i++) { 
     uint j = i; 
     int partSum = sums[j].second.first; 
     int min = sums[j].first.second; 
     while ((j < betweenSums.size()) && std::abs(sums[j].second.first) >= std::abs(betweenSums[j].second.first) && 
      std::abs(sums[j + 1].second.first) >= std::abs(betweenSums[j].second.first)) { 
      partSum += betweenSums[j].second.first + sums[j + 1].second.first; 
      if (min > betweenSums[j].second.second) 
       min = betweenSums[j].second.second; 
      ++j; 
     } 
     if (j != i) { 
      unifiedSums.push_back(
       std::pair<std::pair<uint, uint>, std::pair< int, int>>(std::pair<uint, uint>(sums[i].first.first, sums[j].first.second), 
        std::pair<int, int>(partSum, min)) 
      ); 
      if (j < betweenSums.size()) 
       betweenUnifiedSums.push_back(
        std::pair<std::pair<uint, uint>, std::pair< int, int>>(std::pair<uint, uint>(betweenSums[j].first.first, betweenSums[j].first.second), 
         std::pair<int, int>(betweenSums[j].second.first, betweenSums[j].second.second)) 
       ); 
      i = j; 
      continue; 
     } 

     unifiedSums.push_back(
      std::pair<std::pair<uint, uint>, std::pair< int, int>>(std::pair<uint, uint>(sums[i].first.first, sums[i].first.second), 
       std::pair<int, int>(sums[i].second.first, sums[i].second.second)) 
     ); 
     betweenUnifiedSums.push_back(
      std::pair<std::pair<uint, uint>, std::pair< int, int>>(std::pair<uint, uint>(betweenSums[i].first.first, betweenSums[i].first.second), 
       std::pair<int, int>(betweenSums[i].second.first, betweenSums[i].second.second)) 
     ); 
    } 
    if (unifiedSums[unifiedSums.size() - 1].first.second < sums[sums.size() - 1].first.second) { 
     unifiedSums.push_back(
      std::pair<std::pair<uint, uint>, std::pair< int, int>>(std::pair<uint, uint>(sums[sums.size() - 1].first.first, 
       sums[sums.size() - 1].first.second), 
       std::pair<int, int>(sums[sums.size() - 1].second.first, sums[sums.size() - 1].second.second)) 
     ); 
    } 

} 


void createSums(const std::vector<int> & vec, 
    const double & avg, 
    int & maxSum, 
    std::vector<std::pair<std::pair<uint, uint>, std::pair<int, int>>> & sums, 
    std::vector<std::pair<std::pair<uint, uint>, std::pair<int, int>>> & betweenSums) 
{ 
    const uint len = vec.size(); 
    for (uint i = 1; i < len - 1; i++) { 
     int partialSum = 0; 
     uint j = i; 
     int min = vec[j]; 
     while ((j < len - 1) && ((double)vec[j] < avg && vec[j] < 0)) { 
      partialSum += vec[j]; 
      if (min > vec[j]) 
       min = vec[j]; 
      ++j; 
     } 
     if (j > i) { 
      --j; 
      if (sums.size() == 0) { 
       i = j; 
       continue; 
      } 
      betweenSums.push_back(
       std::pair<std::pair<uint, uint>, std::pair< int, int>>(std::pair<uint, uint>(i, j), std::pair<int, int>(partialSum, min)) 
      ); 
      i = j; 
      continue; 
     } 
     while ((j < len - 1) && (((double)vec[j] >= avg && vec[j] < 0) || vec[j] >= 0)) { 
      partialSum += vec[j]; 
      if (min > vec[j]) 
       min = vec[j]; 
      ++j; 
     } 
     if (j > i) { 
      j--; 

     } 
     sums.push_back(
      std::pair<std::pair<uint, uint>, std::pair< int, int>>(std::pair<uint, uint>(i, j), std::pair<int, int>(partialSum, min)) 
     ); 
     i = j; 
     if (maxSum < partialSum) 
      maxSum = partialSum; 
    } 

    if (betweenSums.size() == sums.size()) { 
     betweenSums.pop_back(); 
    } 

} 


int solution(std::vector<int> & A) 
{ 
    const std::size_t len = A.size(); 
    if (len < 4) 
     return 0; 

    int max = A[1]; 
    int min = A[1]; 
    int sum = A[0];; 
    uint minIndex = 1; 
    for (uint i = 1; i < len - 1; i++) { 
     sum += A[i]; 
     if (A[i] > max) 
      max = A[i]; 
     if (A[i] < min) { 
      min = A[i]; 
      minIndex = i; 
     } 
    } 
    sum += A[len - 1]; 
    if (max <= 0) 
     return 0; 
    if (min >= 0) { 
     return sum - A[0] - A[len - 1] - A[minIndex]; 
    } 

    const double avg = (double)sum/len; 
    std::vector<std::pair<std::pair<uint, uint>, std::pair<int, int>>> sums; 
    std::vector<std::pair<std::pair<uint, uint>, std::pair<int, int>>> betweenSums; 


    std::pair<int, int> partSum; 
    int maxSum = min; 

    createSums(A, avg, maxSum, sums, betweenSums); 

    if (sums.size() == 1) { 
     return sums[0].second.first; 
    } 


    std::vector<std::pair<std::pair<uint, uint>, std::pair<int, int>>> unifiedSums; 
    std::vector<std::pair<std::pair<uint, uint>, std::pair<int, int>>> betweenUnifiedSums; 

    unifySums(sums, betweenSums, unifiedSums, betweenUnifiedSums); 

    if (betweenUnifiedSums.size() == 0) { 
     if (unifiedSums[0].second.first > (unifiedSums[0].second.first - unifiedSums[0].second.second)) 
      return unifiedSums[0].second.first; 
     else 
      return unifiedSums[0].second.first - unifiedSums[0].second.second; 
    } 

    for (uint i = 0; i < betweenUnifiedSums.size(); i++) { 
     int minSoFar = betweenUnifiedSums[i].second.second; 
     int sumSoFar = unifiedSums[i].second.first + betweenUnifiedSums[i].second.first + unifiedSums[i+1].second.first; 
     if (unifiedSums[i].second.first - unifiedSums[i].second.second > maxSum) 
      maxSum = unifiedSums[i].second.first - unifiedSums[i].second.second; 
     if (sumSoFar - minSoFar > maxSum) 
      maxSum = sumSoFar - minSoFar; 
     if (std::abs(betweenUnifiedSums[i].second.first) - std::abs(betweenUnifiedSums[i].second.second) >= std::abs(sumSoFar)) 
      continue; 
     for (uint j = i + 1; j < betweenUnifiedSums.size(); j++) { 
      if (betweenUnifiedSums[j].second.second < minSoFar) 
       minSoFar = betweenUnifiedSums[j].second.second; 
      sumSoFar += betweenUnifiedSums[j].second.first + unifiedSums[j + 1].second.first; 
      if (sumSoFar - minSoFar > maxSum) 
       maxSum = sumSoFar - minSoFar; 
      if (std::abs(betweenUnifiedSums[j].second.first) - std::abs(betweenUnifiedSums[j].second.second) >= std::abs(sumSoFar)) 
       break; 
     } 
    } 

    return maxSum; 
} 
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; 

}