2013-12-18 49 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; 

}