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| = 7P = 2
, difference = |4 − 9| = 5P = 3
, difference = |6 − 7| = 1P = 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.
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.
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;
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
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 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;
}
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;
}
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]
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 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;
}
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;
}
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));
}
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;
}
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/
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
来源:https://stackoverflow.com/questions/19455058/tape-equilibrium-codility-training