Question

I received a codility test the other day for a job, as such I've been practicing using some of the problems from their training page Link

Unfortunately, I've only been able to get 83/100 on the Tape-Equilibrium question:

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.

Write a function that, given a non-empty zero-indexed array A of N integers, returns the minimal difference that can be achieved.

Example: A[0] = 3 A[1] = 1 A[2] = 2 A[3] = 4 A[4] = 3
We can split this tape in four places:
P = 1, difference = |3 − 10| = 7
P = 2, difference = |4 − 9| = 5
P = 3, difference = |6 − 7| = 1
P = 4, difference = |10 − 3| = 7
In this case I would return 1 as it is the smallest difference.

N is an int, range [2..100,000]; each element of A is an int, range [−1,000..1,000]. It needs to be O(n) time complexity,

My code is as follows:

import java.math.*;
class Solution {
public int solution(int[] A) {
    
    long sumright = 0;
    long sumleft = 0;
    long ans;
    
    for (int i =1;i<A.length;i++)
        sumright += A[i];
    
    sumleft = A[0];
    ans =Math.abs(Math.abs(sumright)+Math.abs(sumleft));
    
    for (int P=1; P<A.length; P++)
    {
        if (Math.abs(Math.abs(sumleft) - Math.abs(sumright))<ans)
            ans = Math.abs(Math.abs(sumleft) - Math.abs(sumright));
        sumleft += A[P];
        sumright -=A[P];
    }
    return (int) ans;  
}

I went a bit mad with the Math.abs. The two test areas it fails on are "double" (which I think is two values, -1000 and 1000, and "small". http://codility.com/demo/results/demo9DAQ4T-2HS/

Any help would be appreciated, I want to make sure I'm not making any basic mistakes.

Was it helpful?

Solution

Your solution is already O(N). You need to remove the abs from sumleft and sumright.

if (Math.abs( sumleft - sumright ) < ans)
{
  ans = Math.abs( sumleft - sumright );
}

Also before the second for loop,

ans =Math.abs( sumleft - sumright );

It should work.

OTHER TIPS

100%, in Javascript

var i, ll = A.length, tot = 0, upto = 0, min = Number.MAX_INT;

for (i=0; i<ll; i++) tot += A[i];

for (i=0; i<ll-1; i++)
{
    upto += A[i];
    var a1 = upto, a2 = tot - a1, dif = Math.abs(a1 - a2);
    if (dif < min)
         min = dif;
}

return min;

I found perfect solution for TapeEquilibrium by Cheng on Codesays. I translated it to Java for anybody who is curious about it. Cheng's solution hit 100% on Codility

    public int solution(int[] A) {

    // write your code in Java SE 7
    int N = A.length;

    int sum1 = A[0];
    int sum2 = 0;
    int P = 1;
    for (int i = P; i < N; i++) {
        sum2 += A[i];
    }
    int diff = Math.abs(sum1 - sum2);

    for (; P < N-1; P++) {
        sum1 += A[P];
        sum2 -= A[P];

        int newDiff = Math.abs(sum1 - sum2);
        if (newDiff < diff) {
            diff = newDiff;
        }
    }
    return diff;
}

Consider this 100/100 solution in Ruby:

# Algorithm:
#
# * Compute the sum of all elements.
# * Iterate over elements, maintain left and right weights appropriately.
# * Maintain a minimum of `(left - right).abs`.
def solution(ar)
  sum = ar.inject(:+)
  left = ar[0]
  right = sum - left
  min_diff = (right - left).abs

  1.upto(ar.size - 2) do |i|
    left += ar[i]
    right -= ar[i]
    diff = (right - left).abs
    min_diff = [min_diff, diff].min
  end

  # Result.
  min_diff
end

#--------------------------------------- Tests

def test
  sets = []
  sets << ["1", 1, [1]]
  sets << ["31", 2, [3, 1]]
  sets << ["312", 0, [3, 1, 2]]
  sets << ["[1]*4", 0, [1]*4]
  sets << ["[1]*5", 1, [1]*5]
  sets << ["sample", 1, [3, 1, 2, 4, 3]]

  sets.each do |name, expected, ar|
    out = solution(ar)
    raise "FAILURE at test #{name.inspect}: #{out.inspect} != #{expected.inspect}" if out != expected
  end

  puts "SUCCESS: All tests passed"
end

Here is my 100/100 Python solution:

def TapeEquilibrium(A):
    left = A[0]
    right = sum(A[1::])
    diff = abs(left - right)

    for p in range(1, len(A)):
        ldiff = abs(left - right)
        if ldiff < diff:
            diff = ldiff
        left += A[p]
        right -= A[p]

    return diff

Some C# for ya.

using System;
// you can also use other imports, for example:
// using System.Collections.Generic;
class Solution 
{
    public int solution(int[] A) 
    {
        // write your code in C# with .NET 2.0
        int sumRight = 0;
        for(int i=0; i<A.Length; i++)
        {
            sumRight += A[i];
        }

        int sumLeft = 0;
        int min = int.MaxValue;
        for(int P=1; P<A.Length; P++)
        {
            int currentP = A[P-1];
            sumLeft += currentP;
            sumRight -= currentP;

            int diff = Math.Abs(sumLeft - sumRight);
            if(diff < min)
            {
                min = diff;
            }
        }
        return min;
    }
}

Here is my solution (Java) that i just wrote up for it, very simple to understand and is O(n) and does 100% score on codility:

 public int solution(int[] A) {
    if (A.length == 2)
        return Math.abs(A[0]-A[1]);

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

    int [] s2 = new int[A.length-1];
    s2[A.length-2] = A[A.length-1];
    for (int i=A.length-3;i>=0;i--) {
        s2[i] = s2[i+1] + A[i+1];
    }

    int finalSum = Integer.MAX_VALUE;
    for (int j=0;j<s1.length;j++) {
        int sum = Math.abs(s1[j]-s2[j]);
        if (sum < finalSum)
            finalSum = sum;
    }
    return finalSum;
}

I was doing the same task, but couldn't get better than 50 something points. My algorithm was too slow. So, I searched for a hint and found your solution. I've used the idea of summing the elements in the array only once and got 100/100. My solution is in JavaScript, but it can be easily transformed into Java. You can go to my solution by using the link below.

http://codility.com/demo/results/demo8CQZY5-RQ2/

Please take a look at my code and let me know if you have some questions. I'd be very happy to help you.

function solution(A) {
// write your code in JavaScript 1.6

var p = 1;
var sumPartOne = A[p - 1];
var sumPartTwo = sumUpArray(A.slice(p, A.length));
var diff = Math.abs(sumPartOne - sumPartTwo);

for(p; p < A.length - 1; p++) {
    sumPartOne += A[p];
    sumPartTwo -= A[p];
    var tempDiff = Math.abs(sumPartOne - sumPartTwo);
    if(tempDiff < diff) {
        diff = tempDiff;
    }
}

return diff;

}

function sumUpArray(A) {
var sum = 0;

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

return sum;

}

I was also running into issues getting 83% just like CTB, but for my C++ solution.

For my code, my tape sum was evaluating AFTER updating rightsum and leftsum, but therein lies the problem. In this case, the second loop should evaluate up until P=A.size()-1. Otherwise, you will end up evaluating a tape pair where everything is added to leftsum, and nothing is added to rightsum (which is not allowed according to the problem description).

One possibly nice aspect about my solution below (now fixed to get 100%) is that it does one less evaluation of the sum, compared to a couple solutions above.

#include <stdlib.h>

int solution(vector<int> &A) {
    int sumright = 0;
    int sumleft;
    int result;

for (int i=1; i<A.size(); i++) {
    sumright += A[i];
}
sumleft = A[0];

result = abs(sumleft-sumright);
for (int i=1; i<A.size()-1; i++) {
    sumleft  += A[i];
    sumright -= A[i];
    if (abs(sumleft-sumright)<result) {
        result = abs(sumleft-sumright);
    }
}

return result;
}

My C# code 100/100:

using System;

class Solution
{
    public int solution (int[] A)
    {
        int min = int.MaxValue;

        int sumLeft  = 0;
        int sumRight = ArraySum (A);

        for (int i = 1; i < A.Length; i++)
        {
            int val = A[i - 1];

            sumLeft  += val;
            sumRight -= val;

            int diff = Math.Abs (sumLeft - sumRight);

            if (min > diff)
            {
                min = diff;
            }
        }

        return min;
    }

    private int ArraySum (int[] array)
    {
        int sum = 0;

        for (int i = 0; i < array.Length; i++)
        {
            sum += array[i];
        }

        return sum;
    }
}

100% Score : Tape Equilibrium : Codility : JavaScript

function solution(A) {
    // write your code in JavaScript (ECMA-262, 5th edition)
    var p=0;
    var index=0;
    var leftSum=0;
    var rightSum=0;
    var totalSum=0;
    var N = A.length;

    var last_minimum=100000;

    if(A.length == 2)
        return (Math.abs(A[0]-A[1]));
    if(A.length == 1) 
        return (Math.abs(A[0]));

    for(index=0; index < N; index++)
        totalSum = totalSum + A[index];    


    for(p=1; p <= N-1; p++){
        leftSum += A[p - 1];
        rightSum = totalSum - leftSum;

        current_min = Math.abs(leftSum - rightSum);
        last_minimum = current_min < last_minimum ? current_min : last_minimum;

        if (last_minimum === 0)
            break;
    }
    return last_minimum;
}

Similar algorithm of CTB posted above: This code get 100% score in JAVA;

class Solution {
public int solution(int[] A) {
    int [] diff;
    int sum1;
    int sum2=0;
    int ans, localMin;
    diff = new int[A.length-1];

    //AT P=1 sum1=A[0]
    sum1=A[0];

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

    ans = Math.abs(sum1- sum2);

    for (int p= 1;p<A.length;p++){
        localMin= Math.abs(sum1- sum2);

        if( localMin < ans ){
           ans = localMin;
        }
        //advance the sum1, sum2
        sum1+= A[p];
        sum2-= A[p];
        diff[p-1]=localMin;
    }
    return (getMinVal(diff));    
}  

public int getMinVal(int[] arr){ 
    int minValue = arr[0]; 
    for(int i=1;i<arr.length;i++){
        if(arr[i] < minValue){ 
            minValue = arr[i]; 
        } 
    } 
    return minValue; 
}    

}

this is my 100 score code in Python maybe will help you. You should take a look at if statment its prevent from "double error" if You have N=2 A=[-1,1] when you make sum You get 0 but it should return |-1-1|=|-2|=2

def solution(A):
    a=A 
    tablica=[]
    tablica1=[]
    suma=0
    if len(a) == 2:
        return abs(a[0]-a[1])
    for x in a:
        suma  = suma + x
        tablica.append(suma)
    for i in range(len(tablica)-1):
        wynik=(suma-2*tablica[i])
        tablica1.append(abs(wynik))
    tablica1.sort()
    return tablica1[0]

100% Score in C Program : Codility - TapeEquilibrium

int solution(int A[], int N) {
    int i, leftSum, rightSum, last_minimum, current_min;

    //initialise variables to store the right and left partition sum 
    //of the divided tape

    //begin dividing from position 1 (2nd element) in a 0-based array
    //therefore the left partition sum will start with 
    //just the value of the 1st element
    leftSum = A[0];

    //begin dividing from position 1 (2nd element) in a 0-based array 
    //therefore the right partition initial sum will start with 
    //the sum of all array element excluding the 1st element
    rightSum = 0;
    i = 1;                
    while (i < N) {
        rightSum += A[i];
        i++;
    }
    //get the initial sum difference between the partitions
    last_minimum = abs(leftSum - rightSum);
    if (last_minimum == 0) return last_minimum; //return immediately if 0 diff found

    //begins shifting the divider starting from position 2 (3rd element)
    //and evaluate the diff, return immediately if 0 diff found
    //otherwise shift till the end of array length
    i = 2; //shift the divider
    while (i < N){
        leftSum += A[i-1]; //increase left sum
        rightSum -= A[i-1]; //decrease right sum
        current_min = abs(leftSum - rightSum); //evaluate current diff
        if (current_min == 0) return current_min; //return immediately if 0 diff
        if (last_minimum > current_min) last_minimum = current_min; //evaluate 
                                                                    //lowest min
        i++; //shift the divider
    }   
    return last_minimum; 
}

This is 100 score in ruby

def solution(a)

    right = 0
    left = a[0]
    ar = Array.new

    for i in 1...a.count
        right += a[i]
    end

    for i in 1...a.count

        check = (left - right).abs
        ar[i-1] = check
        left += a[i]
        right -= a[i]

    end

    find = ar.min

    if a.count == 2
        find = (a[0]-a[1]).abs
    end

    find

end

this is what I did!!! // write your code in C# with .NET 2.0

   using System;

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

 {      

 int sumRight = 0, sumleft, result;

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

    int sumLeft = A[0];
    int min = int.MaxValue;
    for(int P=1; P<A.Length; P++)
    {
        int currentP = A[P-1];
        sumLeft += currentP;
        sumRight -= currentP;

        int diff = Math.Abs(sumLeft - sumRight);
        if(diff < min)
        {
            min = diff;
        }
    }
    return min;
   }
  }

Here is an easy solution in C++ (100/100):

#include <numeric>
#include <stdlib.h>

int solution(vector<int> &A)
{
  int left = 0;
  int right = 0;
  int bestDifference = 0;
  int difference = 0;

  left = std::accumulate( A.begin(), A.begin() + 1, 0);
  right = std::accumulate( A.begin() + 1, A.end(), 0);
  bestDifference = abs(left - right);

  for( size_t i = 2; i < A.size(); i++ )
  {
    left += A[i - 1];
    right -= A[i - 1];
    difference = abs(left - right);

    if( difference < bestDifference )
    {
      bestDifference = difference;
    }
  }

  return bestDifference;
}

100% Score in C Program : Codility

int solution(int A[], int N) {
    long p;
    long index;
    long leftSum;
    long rightSum;
    long totalSum=0;

    long last_minimum=100000;
    long current_min;

    if(N==2) return abs(A[0]-A[1]);
    if(N==1) return abs(A[0]);

    for(index=0; index < N; index++)
        totalSum = totalSum + A[index];    

    leftSum = 0; rightSum = 0;

    for (p = 1; p <= N-1; p++) {

        leftSum += A[p - 1];
        rightSum = totalSum - leftSum;        

        current_min = abs((long)(leftSum - rightSum));

        last_minimum = current_min < last_minimum ? current_min : last_minimum;
        if (last_minimum == 0)
            break;
    }
    return last_minimum;
}

int abs(int n) {
    return (n >= 0) ? n : (-(n));
}
def TapeEquilibrium (A):
    n = len(A)
    pos = 0 
    diff= [0]
    if len(A) == 2: return abs(a[0]-a[1])
    for i in range(1,n-1,1):
        diff.sort()
        d = (sum(A[i+1:n-1]) - sum(A[0:i]))
        diff.append(abs(d) + 1)
        if abs(d) < diff[1]:
            pos = i + 1
    return pos
public static int solution(int[] A)
    {
        int SumLeft=0;
        int SumRight = 0;
        int bestValue=0;
        for (int i = 0; i < A.Length; i++)
        {
            SumRight += A[i];
        }
        bestValue=SumRight;
        for(int i=0;i<A.Length;i++)
        {
            SumLeft += A[i];
            SumRight-=A[i];
            if (Math.Abs(SumLeft - SumRight) < bestValue)
            {
                bestValue = Math.Abs(SumLeft - SumRight);
            }

        }
        return bestValue;

    }

The start and end points of the indexes are not correct - hence the 'doubles' test fails, since this test only has a start and end point. Other tests may pass if the set of numbers used does not happen to contain a dependency on the endpoints.

Let N = A.length The sumright is sums from the right. The maximum value of this should exclude A[N] but include A[0]. sumleft - sums from the left. The maximum value of this should include A[0] but exclude A[N]. So the max sumright is incorrectly calculated in the first loop. Similarly in the second loop the max value of sumleft is not calculated since A[0] is excluded. Nadesri points out this problem, but I thought it would be useful if I explicitly pointed out the errors in your code, since that was what you originally asked. Here is my solution written in c99. https://codility.com/demo/results/demoQ5UWYG-5KG/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top