'Tape-Equilibrium Codility Training program

I submitted a solution to Tape Equilibrium problem in Codility. [Codility training][1]

The problem is described as follows:

A non-empty zero-indexed array A consisting of N integers is given. Array A represents numbers on a tape. Any integer P, such that 0 < P < N, splits this tape into two non-empty parts: A[0], A[1], ..., A[P − 1] and A[P], A[P + 1], ..., A[N − 1]. The difference between the two parts is the value of: |(A[0] + A[1] + ... + A[P − 1]) − (A[P] + A[P + 1] + ... + A[N − 1])| In other words, it is the absolute difference between the sum of the first part and the sum of the second part.

The solution I submitted is:

class Solution {
  public int solution(int[] A) {

    long d = A[0] - A[A.length-1];
    int l = 1;
    int r = A.length -2;

    while(l <= r) {
      if (Math.abs(d + A[l]) < Math.abs(d - A[r])) {
        d += A[l];
        l++;
      }
      else {
        d -= A[r];
        r--;
      }
    }
    return (int) Math.abs(d);
  }
}

I achieved 85% accuracy but couldn't get to correct for some use case. Can someone help me to find what's wrong with this solution. Thanks



Solution 1:[1]

The following is my 100% solution:

class Solution {
public int solution(int[] A) {
    // write your code in Java SE 8
    // int idx = 0;
    int sumPre = A[0];
    int sumPost = 0;
    for (int i = 1; i < A.length; i++) {
        sumPost += A[i];
    }
    int difMin = Math.abs(sumPost - sumPre);
    int tempSub = 0;
    for (int i = 1; i < A.length - 1; i++) {
        sumPre += A[i];
        sumPost -= A[i];
        tempSub = Math.abs(sumPost - sumPre);
        if (tempSub < difMin) {
            difMin = tempSub;
            // idx = i+1;

        }
    }
    return difMin;
}
}

I can not find their test input, but I find a weird thing is that when "for(int i = 1; i < A.length - 1; i++) " is changed to " for(int i = 1; i < A.length; i++)", then it will trigger two wrong runs...So it still must be a border value issue. If any one find a test input can break the validity, please share with us, thanks.

Caution: {1,-1} indeed triggered the problem, since P < N, so at least one element should be left in the right part. -> {1,-1},{} is not a valid solution according to the problem definition. Problem solved.

Solution 2:[2]

C# and Linq version for 100% as of May 2021:

  public int solution(int[] A) 
    {

      int left = A[0];
      int right = A.Skip(1).Aggregate((c,x)=> c+=x);
      int min = Math.Abs(left-right);

      for(int i=1; i < A.Length-1; i++) 
      {
        left+=A[i];
        right-=A[i];
        min = Math.Min(min,Math.Abs(left-right));
      }
 
      return min;
    }

Solution 3:[3]

I also tried and got only 83%. My solution:

class Solution {
    public int solution(int[] A) {

        int[] leftSums = new int[A.length];
        for (int i = 0; i < leftSums.length; i++) {
            leftSums[i] = 0;
        }

        int sum = 0;
        for (int i = 0; i < A.length; i++) {
            sum  += A[i];
            leftSums[i] = sum;
        }
        /*
        for (int i = 0; i < leftSums.length; i++) {
            if (i == 0) {
                System.out.print("Left Sums Array is : [");
            }

            if (i == leftSums.length - 1) {
                System.out.println(leftSums[i] + "]");
            }
            System.out.print(leftSums[i] + ", ");
        }
        */
        final int total = sum;
        //System.out.println("Total is " + total);
        int minDiff = Integer.MAX_VALUE;
        int currDiff = 0;
        for (int i = 0; i < leftSums.length; i++) {
            currDiff = Math.abs(leftSums[i] - (total - leftSums[i]));
            if (currDiff < minDiff) {
                minDiff = currDiff;
            }
        }

        return minDiff;
    }
}

Below are those which failed for correctness. double two elements 1.280 s WRONG ANSWER got 0 expected 2000

small small elements 1.304 s WRONG ANSWER got 0 expected 20

I tested myself for 2 elements and it worked for me.

Solution 4:[4]

I share my 100% score Java solution:

class Solution {
public int solution(int[] A) {
        final int size = A.length;
        long sumMin = (int)A[0];
        long sumMax = 0;
        for (int i = 1; i < size; i++) {
            sumMax += (int)A[i];
        }
        int minDif = (int)Math.abs(sumMax - sumMin);
        for (int i = 1; i < size; i++) {
            int dif = (int)Math.abs(sumMax - sumMin);
            if (dif < minDif) {
                minDif = dif;
            }
            sumMin += A[i];
            sumMax -= A[i];
        }
        return minDif;
    }
}

The trick is that looping the array twice your complexity is 2N, which is O(N).

Addition results should be 'long' in order not to have problems with big extremes.

Solution 5:[5]

For %83 results, the problem is it says "splits this tape into two non-empty parts". So if you split for A[0], your first array will be empty. So you should start with A[1].

Solution 6:[6]

Ruby 100%

def solution(a)
  left = a.inject(:+)
  right = 0
  a[0...-1].inject(Float::INFINITY) do |min, el|
    left -=el
    right += el
    candidate = (right-left).abs
    min < candidate ? min : candidate 
  end
end

Solution 7:[7]

You can actually do that, with one loop in C#.

Add Linq:

 public int solution(int[] A)
    {

        // write your code in C# 6.0 with .NET 4.5 (Mono)
            long sum = A.Sum(p => (long)p);
            int val1 = Convert.ToInt32(A.GetValue(0));
            int val2 = Convert.ToInt32(sum - val1);
            int result = Math.Abs(val1 - val2);
            for (int i = 1; i < A.Length-1; i++)
            {
                val1 += Convert.ToInt32(A.GetValue(i));
                val2 -= Convert.ToInt32(A.GetValue(i));
                if (result > Math.Abs(val1 - val2))
                {
                    result = Math.Abs(val1 - val2);
                }
            }


        return result;
    }

Solution 8:[8]

Counterexample for user699681: A = {0, 1, 2, -5, 2}, and for Ism: A = {1, -1}.

Solution 9:[9]

TapeEquilibrium in C

int solution(int A[], int N) {
    // write your code in C90
    long int s_r=0,s_l=A[0],sum=A[0];
    int i,min=11111111,r;

    for(i=1;i<N;i++)
        sum+=A[i];

    for(i=1;i<N;i++)
    {
        s_r=sum-s_l;
        r=(int)(s_l-s_r);
        if(r<0) r=-r;
        if(min>r)min=r;
        if(min==0)break;
        s_l=sum-s_r+A[i];
    } 
    return min;
}

Solution 10:[10]

.. Or even a bit shorter to get 100%

public int solution(int[] A) {
    int sumMin = A[0];
    int sumMax = 0;

    for (int i = 1; i < A.length; i++) {
        sumMax += A[i];
    }

    int minDif = Math.abs(sumMin - sumMax);
    for (int i = 1; i < A.length - 1; i++) {
        sumMin += A[i];
        sumMax -= A[i];
        minDif = Math.min(minDif, Math.abs(sumMin - sumMax));
    }

    return minDif;
}

Solution 11:[11]

Here's my implementation using Java 8 IntStream to simplify the sum process...
100% Correct, 100% Performance.

import java.util.stream.IntStream;

public class TapeEquilibrium {

    public static int diffIndex( int[] A ) {

        long lower = 0, diff = 0, higher = IntStream.of( A ).asLongStream().sum(), minDiff = Integer.MAX_VALUE;
        for(int i = 0; i < A.length-1; i++) {
            lower += A[i];
            higher -= A[i];
            diff = Math.abs( higher - lower);
            if( diff < minDiff  ) {
                minDiff = diff;
            }
        }
        return (int) minDiff;
    }


    public static void main( String[] args ) {

        int[] A = { 3, 1, 2, 4, 3 };
        System.out.println( diffIndex( A ) );

    }
}    

Solution 12:[12]

here is my Solution with 100% correctness & performance

int solution(int A[], int N) 
{
    int sum,i;
    sum=0;
    for(i=0;i<N;i++)
    {
        sum+=A[i];
        A[i]=sum;
    }

    int min_diff=abs(sum-A[0]*2);
    for(i=0;i<N-1;i++)
    {
        int tmp;
        tmp=abs(sum-A[i]*2);

        if(tmp<min_diff)
            min_diff=tmp;
    }

    return min_diff;
}

Solution 13:[13]

Try this one:

Class Solution {

    public int solution(int[] A) {

        int sum1 = 0;
        int sum2 = 0;
        int sum3 = 0;
        int len = A.length;
        int min = 1 ;

        for(int i=0; i<len; i++){
                sum2 += A[i];
        }

        for(int i=0; i< len-1 ; i++){

            sum1 += A[i];
            sum3 = sum2-sum1;

            if( min > Math.abs(sum1- sum3)){
                min = Math.abs( sum1 - sum3);
            }

        }

        return min;
    }

}

Solution 14:[14]

Here is 100% in scala.

def solution(A: Array[Int]): Int = {

    //get the whole sum
    val allSum = A.sum

    //calculate left and right sum
    var sumLeft = A(0)
    var sumRight = allSum - sumLeft

    //set initial diff for P=1
    var minDiff = math.abs(sumLeft-sumRight)  //difference

    // loop for all P after the initial P position
    for(p <- 1 to A.length-2){

      //recalculate values
      sumLeft += A(p)
      sumRight -= A(p)

      if(math.abs(sumLeft-sumRight) < minDiff){
        // if difference is smaller then save new min diff
        minDiff = math.abs(sumLeft-sumRight)
      }

    }

    minDiff
  }

Performance: https://codility.com/demo/results/trainingZNZCZN-AGC/

Solution 15:[15]

    long sumofall = 0, leftsideSum = A[0], rightsidesum=0;
    int x,LR = 0;
    ArrayList listResult = new ArrayList();
    for(x=0;x<A.Length;x++)
    {
        sumofall+= A[x];
    }

    for(x=1;x<A.Length;x++)
    {
        rightsidesum = sumofall-leftsideSum;
        LR = (int)(rightsidesum - leftsideSum);
        if(LR < 0)
        {
            LR=-LR;
        }
        listResult.Add(LR);
        leftsideSum+=A[x];
    }
    listResult.Sort();
    return Convert.ToInt32(listResult[0].ToString());
}

Solution 16:[16]

I share my 100% solution using Java 8.

public class TapeEquilibrium {

public int tapeEquilibrium(int[] A) {
    final int N = A.length;
    long minimalSum = (int) A[0];

    int[] rightSide = Arrays.copyOfRange(A, 1, N);
    long maximalSum = IntStream.of(rightSide).sum();

    int minimalDifference = (int) Math.abs(maximalSum - minimalSum);
    for (int i = 1; i < N; i++) {
        int difference = (int) Math.abs(maximalSum - minimalSum);
        minimalDifference = difference < minimalDifference ? difference : minimalDifference;
        minimalSum += A[i];
        maximalSum -= A[i];
    }
    return minimalDifference;
}

}

Solution 17:[17]

Here is my C# solution. Score 100%

        if (A == null || A.Length == 0)
        {
            return 0;
        }

        int d1 = 0;
        int d2 = A.Sum();
        int p = 1;
        int x = int.MaxValue;

        // Replaced using A.sum();
        //for (int i=0; i < A.Length; i++)
        //{
        //        d2 += A[i];
        //}

        for (int j = 0; j < A.Length; j++)
        {
            if (j < p)
            {
                d1 += A[j];
            }

            int ad = Math.Abs(d1 - (d2 - d1));

            x = Math.Min(x, ad);

            if (p == A.Length -1) { break; }
            p++;
        }

        return x;

Solution 18:[18]

Below is my solution which got 100% . As most of you guys did I first got the sum of the array then go through it while adding up left and right parts and then getting the absolutes of them and putting the results into a map then checking the map for the minimum value .

    int totalLeft = 0;
    int totalRight = 0;
    int total = 0;
    int result = 0;
    Map<Integer, Integer> map = new HashMap<Integer, Integer>();

    for (int i = 0; i < A.length; i++) {
        total += A[i];
    }

    for (int i = 0; i < A.length - 1; i++) {

        totalRight = total - (A[i] + totalLeft);
        totalLeft += A[i];

        result = Math.abs(totalLeft - totalRight);

        map.put(i, result);


    }


    return Collections.min(map.values());

Solution 19:[19]

TapeEquilibrium in Swift 4

public func solution(_ A : inout [Int]) -> Int {
    let P = 1
    var splitIndex = P
    var firstPartSum = A[splitIndex - 1]
    var secondPartSum = Array(A[splitIndex..<A.count]).reduce(0, +)
    var minimalDifference =  abs(firstPartSum - secondPartSum)

    if minimalDifference == 0 {
        return minimalDifference
    }

    splitIndex += 1

    while splitIndex < A.count {
        firstPartSum += A[splitIndex - 1]
        secondPartSum -= A[splitIndex - 1]

        let dif = abs(firstPartSum - secondPartSum)

        if dif == 0 {
            return dif
        }

        if dif < minimalDifference {
            minimalDifference = dif
        }

        splitIndex += 1
    }

    return minimalDifference
}

Solution 20:[20]

No one posted Javascript solution yet so here is mine with comments:

// you can write to stdout for debugging purposes, e.g.
// console.log('this is a debug message');

function solution(A) {
  // write your code in JavaScript (Node.js 8.9.4)

  // Making it shorter.
  let len = A.length;

  // Definitely need to store, and initialise first value.
  let left = new Array(len);
  left[0] = A[0];

  // Same as above, but initialise for last value.
  let right = new Array(len);
  right[len - 1] = A[len - 1];

  let trackLowest = Number.MAX_SAFE_INTEGER;

  // One shot calculate for both at any element (from 'outwards' 'in').
  // Note there is 2 elements at least, and we already preset the first
  // element, so we start and build from index 1.
  for (let i = 1; i < len; ++i) {
    left[i] = left[i - 1] + A[i];
    right[len - 1 - i] = right[len - i] + A[len - 1 - i];
  }

  // Once the above is done, it's time to calculate the difference.
  // If I am at index 0, then I want sum of index 0 AND left, and sum of index
  // 1 and right (note not index 0 also).
  // We stop before len - 1 because that's the rules and the sum of right will
  // have been out of bounds if we want difference for last index, isn't it?
  for (let i = 0; i < len - 1; ++i) {
    let smallestDiff = Math.abs(left[i] - right[i + 1]);
    if (smallestDiff < trackLowest) {
      trackLowest = smallestDiff;
    }
  }

  return trackLowest;
}

Basically sum up as you walk the loop simultaneously for the left and right side. Once done, just get the difference, that's it. O(n) complexity.

Solution 21:[21]

My 100% JavaScript solution with O(N) time complexity (should be pretty self-explanatory):

function solution(A) {

     let left = 0;
     let right = A.reduce((sum, cur) => sum + cur, 0);
     let min = Infinity;

     for (let p = 0, len = A.length - 1; p < len; p++) {
         left += A[p];
         right -= A[p];
         min = Math.min(min, Math.abs(left - right));
     }

     return min;

}

Solution 22:[22]

Here mine in Java, // got 91% because "int totalRight = (Arrays.stream(A).sum() - A[0]);" take too long to load

int totalLeft = A[0];
    int totalRight = (Arrays.stream(A).sum() - A[0]);
    //int afterMinus = 0;
    int min = 0;

    min = Math.abs(totalLeft - totalRight);

    for(int i=1; i<(A.length-1); i++) {
        //for(int j=A.length; j>0; j--) {
        totalLeft += A[i];
        totalRight -= A[i];
        //System.out.println("totalLeft = "+ totalLeft);
        //System.out.println("totalRight = "+ totalRight);
        if(Math.abs(totalLeft - totalRight) < min) {
            //System.out.println("min = "+ min);
            min = Math.abs(totalLeft - totalRight);
        }
    }

    return min;

// got 100% because change "int totalRight = (Arrays.stream(A).sum() - A[0]);" into for loop

//int totalSum = Arrays.stream(A).sum();
    int totalLeft = A[0];
    int totalRight = 0;
    //int afterMinus = 0;
    int min = 0;

    for(int i=1; i<A.length; i++) {
        totalRight += A[i];
    }
    min = Math.abs(totalLeft - totalRight);

    for(int i=1; i<(A.length-1); i++) {
        //for(int j=A.length; j>0; j--) {
        totalLeft += A[i];
        totalRight -= A[i];
        //System.out.println("totalLeft = "+ totalLeft);
        //System.out.println("totalRight = "+ totalRight);
        if(Math.abs(totalLeft - totalRight) < min) {
            //System.out.println("min = "+ min);
            min = Math.abs(totalLeft - totalRight);
        }
    }

    return min;

Well, from 91% to 100%, thanks to @sebadagostino after surfing for almost 2 hours for the logic and hints.