Recently, I tried to solve the Max Double Slice Sum problem in codility which is a variant of max slice problem. My Solution was to look for a slice that has maximum value when its minimum value is taken out. So I implemented max slice, but on the current slice took out the minimum number.
My score was 61 of 100 as it failed during some of the tests, mainly the tests on array including both negative and position numbers.
Could you help me to figure out why the code failed or if there is a better solution for the problem?
The problem is as follows:
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.
And my code is as follows:
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;
}
}
If I have understood the problem correctly, you want to calculate the maximum sum subarray with one element missing.
Your algorithm shall not work for the following case:
1 1 0 10 -100 10 0
In the above case, your algorithm shall identify 1, 1, 0, 10 as the maximum sum sub array and leave out 0 to give 12 as the output. However, you can have 1, 1, 0, 10, -100, 10 as the answer after leaving out -100.
You can use a modified form of Kadane's algorithm that calculates the MAX Sum subarray ending at each index.
For each index, calculate the max_sum_ending_at[i] value by using Kadane's algorithm in forward direction.
For each index, calculate the max_sum_starting_from[i] value by using Kadane's algorithm in reverse direction.
Iterate these arrays simultaneously and choose the 'Y' that has the maximum value of
max_sum_ending_at[Y-1] + max_sum_starting_from[Y+1]
Hello this implementacion has 100 score
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 ;
This is a Java 100/100 Solution:
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;
}
}
You can find more information going to this Wikipedia link and in the Programming Pearls book.
Here is my solution
https://github.com/dinkar1708/coding_interview/blob/master/codility/max_slice_problem_max_double_slice_sum.py
Codility 100% in Python
def solution(A):
"""
Idea is use two temporary array and store sum using Kadane’s algorithm
ending_here_sum[i] - the maximum sum contiguous sub sequence ending at index i
starting_here_sum[i] - the maximum sum contiguous sub sequence starting with index i
Double slice sum should be the maximum sum of ending_here_sum[i-1]+starting_here_sum[i+1]
Reference -
https://rafal.io/posts/codility-max-double-slice-sum.html
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].
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.
"""
ar_len = len(A)
ending_here_sum = [0] * ar_len
starting_here_sum = [0] * ar_len
# the maximum sum contiguous sub sequence ending at index i
for index in range(1, ar_len - 2): # A[X + 1] + A[X + 2] + ... + A[Y - 1]
ending_here_sum[index] = max(ending_here_sum[index - 1] + A[index], 0)
# the maximum sum contiguous sub sequence starting with index i
for index in range(ar_len - 2, 1, -1): # A[Y + 1] + A[Y + 2] + ... + A[Z - 1]
starting_here_sum[index] = max(starting_here_sum[index + 1] + A[index], 0)
# Double slice sum should be the maximum sum of ending_here_sum[i-1]+starting_here_sum[i+1]
max_slice_sum = ending_here_sum[0] + starting_here_sum[2]
for index in range(1, ar_len - 1):
max_slice_sum = max(max_slice_sum, ending_here_sum[index - 1] + starting_here_sum[index + 1])
return max_slice_sum
C# solution 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;
}
Without using extra memory, 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;
}
Javascript implementation based on Abhishek Bansal's solution.100/100 on 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;
}
The most clear Python solution among others:
def solution(A):
mid = 1
total = 0
max_slice = 0
for idx, end in enumerate(A[2:-1], start=2):
if total < 0:
mid = idx
total = 0
elif total == 0 and A[idx - 1] > A[mid]:
mid = idx - 1
total = end
else:
if A[mid] > end:
total += A[mid]
mid = idx
else:
total += end
max_slice = max(max_slice, total)
return max_slice
Using the idea from http://en.wikipedia.org/wiki/Maximum_subarray_problem
and Abhishek Bansal's answer above. 100% test pass:
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;
}
}
Vb.net version of the above solution is as below:
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
Here is an alternative solution to the proposed by me before, more readable and understandable:
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;
}
Well, I have my solution, may be not the best one bit 100%/100%, according to codility requierments.
#include<vector>
#include<unordered_map>
#include<algorithm>
using namespace std;
int solution(vector<int> &A) {
unordered_map<size_t, int> maxSliceLeftToRight;
maxSliceLeftToRight[1] = 0;
unordered_map<size_t, int> maxSliceRightToLeft;
maxSliceRightToLeft[A.size() - 2] = 0;
int sum = 0;
for (size_t i = 2; i < A.size() - 1; i++) {
int tmpSum = max(sum + A[i - 1], 0);
sum = max(A[i - 1], tmpSum);
maxSliceLeftToRight[i] = sum;
}
sum = 0;
for (size_t i = A.size() - 3; i > 0; i--) {
int tmpSum = max(sum + A[i + 1], 0);
sum = max(A[i + 1], tmpSum);
maxSliceRightToLeft[i] = sum;
}
int maxDoubleSliceSum = 0;
for (auto & entry : maxSliceLeftToRight) {
int maxRight = maxSliceRightToLeft[entry.first];
if (entry.second + maxRight > maxDoubleSliceSum)
maxDoubleSliceSum = entry.second + maxRight;
}
return maxDoubleSliceSum;
}
Here 100% in python,
might not be as elegant as some other solutions above, but considers all possible cases.
def solution(A):
#Trivial cases
if len(A)<=3:
return 0
idx_min=A.index(min(A[1:len(A)-1]))
minval=A[idx_min]
maxval=max(A[1:len(A)-1])
if maxval<0:
return 0
if minval==maxval:
return minval*(len(A)-3)
#Regular max slice if all numbers > 0
if minval>=0:
max_ending=0
max_slice=0
for r in range(1,len(A)-1):
if (r!=idx_min):
max_ending=max(0,A[r]+max_ending)
max_slice = max(max_slice, max_ending)
return max_slice
#Else gets more complicated
else :
#First remove negative numbers at the beginning and at the end
idx_neg=1
while A[idx_neg] <= 0 and idx_neg<len(A) :
A[idx_neg]=0
idx_neg+=1
idx_neg=len(A)-2
#<0 , 0
while A[idx_neg] <= 0 and idx_neg > 0 :
A[idx_neg]=0
idx_neg-=1
#Compute partial positive sum from left
#and store it in Left array
Left=[0]*len(A)
max_left=0
for r in range(1,len(A)-1):
max_left=max(0,A[r]+max_left)
Left[r]=max_left
#Compute partial positive sum from right
#and store it in Right array
max_right=0
Right=[0]*len(A)
for r in range(len(A)-2,0,-1):
max_right=max(0,A[r]+max_right)
Right[r]=max_right
#Compute max of Left[r]+Right[r+2].
#The hole in the middle corresponding
#to Y index of double slice (X, Y, Z)
max_slice=0
for r in range(1,len(A)-3):
max_slice=max(max_slice,Left[r]+Right[r+2])
return max_slice
pass
Think I got it based on Moxis Solution. Tried to point out the Intension.
class Solution {
public int solution(int[] A) {
int n = A.length - 1;
// Array with cummulated Sums when the first Subarray ends at Index i
int[] endingAt = new int[A.length];
int helperSum = 0;
// Optimal Subtotal before all possible Values of Y
for(int i = 1; i < n; ++i ) {
helperSum = Math.max(0, A[i] + helperSum);
endingAt[i] = helperSum;
}
// Array with cummulated Sums when the second Subarray starts at Index i
int[] startingAt = new int[A.length];
helperSum = 0;
// Optimal Subtotal behind all possible Values of Y
for(int i = (n - 1); i > 0; --i ) {
helperSum = Math.max(0, A[i] + helperSum);
startingAt[i] = helperSum;
}
//Searching optimal Y
int sum = 0;
for(int i = 0; i < (n - 1); ++i) {
sum = Math.max(sum, endingAt[i] + startingAt[i+2]);
}
return sum;
}
}
Here is the Python version of the proposed solution with complexity O(N) and %100 correctness and performance.
#Find the maximal sum of any double slice.
#https://app.codility.com/programmers/lessons/9-
#maximum_slice_problem/max_double_slice_sum/
import sys
def solution(A):
n=len(A)
max_sum_endingat=[0]*n
max_sum_startat=[0]*n
if(n<=3):
return 0
else:
for i in range(1,n-1):
max_sum_endingat[i] =max(0,max_sum_endingat[i-1] + A[i])
for i in range(n-2,0,-1):
max_sum_startat[i] =max(0,max_sum_startat[i+1] + A[i])
max_double=-sys.maxsize
for k in range(1,n-1):
max_double=max(max_double,max_sum_endingat[k-1]+max_sum_startat[k+1])
return max_double
This is my solution. It got 92%. Its a modified version of the original concept except I'm keep track of a minimal value to use as the position Y, and I'm shifting the sum of the entire interval accordingly.
Note: If anyone has any idea why it's only 92% feel free to let me know
class Solution {
public int solution(int[] A) {
// write your code in Java SE 8
int max = -10001, sum = 0, min=A[1];
for(int i = 1; i < A.length-1; i++){
sum += A[i];
min = Math.min(A[i], min);
max = Math.max(sum-min, max);
if(sum - min < 0){
sum = 0;
min = A[i+1];
}
}
return max;
}
}
Single-loop, no extra memory dynamic programming solution in Python:
def solution(A):
max_gap_sum = 0
gapless_sum, gap_sum = 0, float("-inf")
for v in A[1:-1]:
gapless_sum, gap_sum = max(gapless_sum + v, 0), max(gap_sum + v, gapless_sum)
max_gap_sum = max(max_gap_sum, gap_sum)
return max_gap_sum
Java solution, 100/100
class Solution {
public int solution(int[] A) {
// write your code in Java SE 8
int maxEnd = 0, maxSlice = Integer.MIN_VALUE;
for(int val : A) {
maxEnd = Math.max(val, maxEnd + val);
maxSlice = Math.max(maxSlice, maxEnd);
}
return maxSlice;
}
}
Related
There is a natural number n. You have to find a pair of natural numbers x, y whose sum is n and also have the least energy among other pair having the sum n.
Energy(x) = sum of all digits of x
Total Energy = Energy(x) + Energy(y)
1 <= n <= 10^9
For eg,
n = 10000
A few pairs:
5000 + 5000 -> Energy = 10
1000 + 9000 -> Energy = 10
9999 + 1 -> Energy = 37
2999 + 7001 -> Energy = 37
So possible answers are:
(5000, 5000), (1000, 9000) etc
I have tried the solution noted above so far but it is not an optimized approach
I will loop from 1 to n-1 and and try all pairs and check their sum of digits but it will take too much time for big numbers.
e.g.
n= 50
1,49--> energy 14
2,48--> energy 14
3,47--> energy 14
4,46--> energy 14
5,45--> energy 14
.
.
.
.
10,40-->energy 5
(Edited) After some thought, I arrived at the following solution. Would appreciate if somebody can come up with a better solution
public int sum(int n) {
String s = String.valueOf(n);
if (isNonZeroOnlyOne(n)) {
int num = getNonZeroNo(n);
if (num == 1)
return 10;
return num;
}
return calculateEnergy(s);
}
private int calculateEnergy(String s) {
int sum = 0;
for(int i=0; i<s.length(); i++)
sum += s.charAt(i) - '0';
return sum;
}
private int getNonZeroNo(int n) {
String s = String.valueOf(n);
for(int i=0; i<s.length(); i++) {
char c = s.charAt(i);
if (c != '0')
return c-'0';
}
return '0';
}
private boolean isNonZeroOnlyOne(int n) {
String s = String.valueOf(n);
int count = 0;
for(int i=0; i<s.length(); i++) {
char c = s.charAt(i);
if (c != '0')
count++;
if (count > 1)
return false;
}
return true;
}
It's simple.
if n is of type 10^x then the answer is 10. otherwise answer is the sum of digits of n.
The idea here is to break down the number into a pair containing digits less than that are present in n. if you break down into smaller digits then sum remains the same as the original number.
example for 7= 1-6,2-5,3-4.
for a number like 100, 1000....
digit 1 can't be broken down into further pairs, so we try to make 10 as the sum of digit so that the sum becomes n.
like for 10=5-5,2-8,3-7
100=20-80,40-60
for other numbers, like 123
it can be broken into 100-23, 120-3, 111-12... all will give you sum 6. which is the sum of digits of the original number.
if you try to break down into further pairs like 80-43, 52-71, you will see that the digit sum increases as you broken down to a number containing digits which is higher than those are present in n. like 8 4,5,7 are greater than 3.
The least energy can be derived by a simple formula.
1) Given N > 100, the pair can be N-100 and 100 , and the energy will be same as the energy of N.
eg : N = 500 ; Pair = 400 and 100 ; Energy = 5
2) N >=10 and N <=100 , pair = N-10 and 10
eg : N = 50 ; Pair = 40 and 10 ; Energy = 5
3) N >=2 and N <=10 , pair = N-1 and 1
eg : N = 5 ; Pair = 4 and 1 ; Energy = 5
I spent more than 1 hour on this problem. What should be answer for n = 1? So I think n should be greater than 1. I am assuming n > 1.
So brute-force solution won't work here because n is huge enough. So you need more optimized solution. You need to think think about how many times you have to carry 1 in the sum to make n. It is at most 9 times!
If you have some basic idea with digit-dp(Dynamic Programming) then this problem is easy. Try to place all possible digit on a place of n and take minimum energy among them. This problem is easy when you fully understand digit-dp technique. You can learn it from here and here.
For practice, you can find a lot of problems here (Dynamic programming section).
For your references, I wrote this code just now and it is working properly. Hope you can use this as a reference.
#include <bits/stdc++.h>
using namespace std;
const string INF_STRING = "9999999";
const int INF_INT = 9999999;
pair<string, int> INF = make_pair(INF_STRING, INF_INT);
int nod;
int digits[10];
int num_of_digits(int a) {
int cnt = 0;
while(a) {
digits[cnt] = a % 10;
a = a / 10;
cnt++;
}
return cnt;
}
pair<string, int> dp[10][2][2][2];
pair<string, int> solve(int ind, int carry, bool is1, bool is2) {
if(ind >= nod) {
if(carry != 0 || !is1 || !is2) return INF;
return make_pair("", 0);
}
pair<string, int> &ret = dp[ind][carry][is1][is2];
if(ret.second != -1) return ret;
ret = INF;
for(int i = 0; i < 10; i++) {
for(int j = 0; j < 10; j++) {
int s = (i + j + carry);
pair<string, int> cur = INF;
if(s % 10 == digits[ind]) {
cur = solve(ind + 1, s / 10, is1 || (i > 0? 1:0), is2 || (j > 0? 1:0));
}
if((cur.second + i + j) < ret.second) {
ret.second = cur.second + i + j;
ret.first = cur.first + (char)(i + '0');
}
}
}
return ret;
}
int stringToInt(string num) {
stringstream ss;
ss<<num;
int ret;
ss >> ret;
return ret;
}
int main() {
int i, t, cases = 1, j, k, pos;
int n;
scanf("%d", &n);
nod = num_of_digits(n);
for(int i = 0; i < 10; i++) {
for(int j = 0; j < 2; j++) {
dp[i][j][0][0] = make_pair(INF_STRING, -1);
dp[i][j][0][1] = make_pair(INF_STRING, -1);
dp[i][j][1][0] = make_pair(INF_STRING, -1);
dp[i][j][1][1] = make_pair(INF_STRING, -1);
}
}
pair<string, int> res = solve(0, 0, 0, 0);
string num1_str = res.first;
int num1 = stringToInt(num1_str);
int num2 = n - num1;
printf("Minimum Energy: %d\n", res.second);
printf("Num1 = %d, Num2 = %d\n", num1, num2);
return 0;
}
/*
Input:
10000
Output:
Minimum energy: 10
Num1 = 1000, Num2 = 9000
*/
Here is the answer in javascript in simple way.
function calculateEnergy(n) {
let e = 0
while(n > 0) {
e += n % 10
n = Math.floor(n / 10)
}
return e
}
function countMinEnergy(n) {
let minE = n
let i = 1
while(i <= n/2) {
let e = calculateEnergy(i) + calculateEnergy(n - i)
minE = e < minE ? e : minE
i++
}
return minE
}
countMinEnergy(4325)
Here is scala solution
object LeastEnergyPair extends App {
private def getCountOfPair(array: Array[Int],sum: Int): mutable.Set[(Int, Int)] = {
val seen = mutable.Set[Int]()
val out = mutable.Set[(Int,Int)]()
array map { x =>
val target = sum - x
if (seen.contains(target) || target*2 == sum)
out += ((Math.min(x,target),Math.max(x,target)))
else
seen += x
}
println(out)
out
}
private def sum(i:Int): Int = i.toString.toCharArray.map(_.asDigit).sum
def findLeastEnergyPair(a: mutable.Set[(Int,Int)]): (Int,Int) = {
var min = Int.MaxValue
var minPair = (0,0)
a.foreach {
case (i,j) =>
if (sum(i) + sum(j) < min) {
min = sum(i) + sum(j)
minPair = (i,j)
println(s"$min ----- $minPair")
}
}
minPair
}
println(findLeastEnergyPair(getCountOfPair((1 to 10000).toArray, 10000)))
}
The below logic will cover all scenarios
if (N%10 == 0) {
x1= (N/10);
x2 = N-x1
}else{
x1 = N-10;
x2 = 10;
}
I am solving Codility problem CountSemiprimes: Count the semiprime numbers in the given range [a..b].
Task description
A prime is a positive integer X that has exactly two distinct divisors: 1 and X. The first few prime integers are 2, 3, 5, 7, 11 and 13.
A semiprime is a natural number that is the product of two (not necessarily distinct) prime numbers. The first few semiprimes are 4, 6, 9, 10, 14, 15, 21, 22, 25, 26.
You are given two non-empty arrays P and Q, each consisting of M integers. These arrays represent queries about the number of semiprimes within specified ranges.
Query K requires you to find the number of semiprimes within the range (P[K], Q[K]), where 1 ≤ P[K] ≤ Q[K] ≤ N.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..50,000];
M is an integer within the range [1..30,000];
each element of arrays P, Q is an integer within the range [1..N];
P[i] ≤ Q[i].
My solution
My current score is 66% and problem is preformance for large data set:
large random, length = ~30,000
all max ranges
Test says, that it should take about 2sec, but my solution takes over 7sec.
This is my current solution
class Solution {
private static List<Integer> getPrimes(int max) {
List<Integer> primes = new ArrayList<>(max / 2);
for (int i = 0; i < max; i++)
if (isPrime(i))
primes.add(i);
return primes;
}
private static boolean isPrime(int val) {
if (val <= 1)
return false;
if (val <= 3)
return true;
for (int i = 2, sqrt = (int)Math.sqrt(val); i <= sqrt; i++)
if (val % i == 0)
return false;
return true;
}
private static boolean[] getSemiPrimes(int N) {
List<Integer> primes = getPrimes(N);
boolean[] semiPrimes = new boolean[N + 1];
for (int i = 0; i < primes.size(); i++) {
if (primes.get(i) > N)
break;
for (int j = i; j < primes.size(); j++) {
if (primes.get(j) > N || N / primes.get(i) < primes.get(j))
break;
int semiPrime = primes.get(i) * primes.get(j);
if (semiPrime <= N)
semiPrimes[semiPrime] = true;
}
}
return semiPrimes;
}
public static int[] solution(int N, int[] P, int[] Q) {
boolean[] semiPrimes = getSemiPrimes(N);
int[] res = new int[P.length];
for (int i = 0; i < res.length; i++)
for (int j = P[i]; j <= Q[i]; j++)
if (semiPrimes[j])
res[i]++;
return res;
}
}
Any ideas about improving performance? My last one was to remove Set for holding semi-primes with array. It helped me to solve couple of performance tests.
A Java solution which scores 100% is as follow:
Find the set of prime numbers which their products is not greater than N
create semi-prime from them as a bit wise array of 0 and 1
create a prefix sum of the semi-primes
calculate the queries from P[i] to Q[i] in O(M)
The whole algorithm is of O(N * log(log(N)) + M) stated by the Codility's test result evaluation.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class CountSemiPrime {
public static void main(String[] args) {
int[] P = new int[] {1, 4, 16};
int[] Q = new int[] {26, 10, 20};
System.out.println( Arrays.toString( new CountSemiPrime().solution( 26, P, Q ) ) );
}
public int[] solution(int N, int[] P, int[] Q) {
Integer[] primes = sieve(N/2+1);
int[] temp = new int[N+1];
for (int i = 0; i < primes.length; i++) {
for (int j = 0; j < primes.length; j++) {
int semiPrime = primes[i] * primes[j];
if(semiPrime <= N)
temp[semiPrime] = 1;
}
}
int[] prefix = new int[N+1];
for (int i = 1; i < temp.length; i++) {
prefix[i] = temp[i] + prefix[i-1];
}
int[] retVal = new int[P.length];
for (int i = 0; i < retVal.length; i++) {
retVal[i] = prefix[Q[i]] - prefix[P[i]-1];
}
return retVal;
}
public Integer[] sieve(int n) {
boolean[] temp = new boolean[n+1];
for (int i = 0; i < temp.length; i++) {
temp[i] = true;
}
temp[0] = temp[1] = false;
int i = 2;
while (i * i <= n) {
removeProducts( temp, i );
i++;
}
List<Integer> ret = new ArrayList<>();
for (int j = 0; j < temp.length; j++) {
if(temp[j])
ret.add( j );
}
return ret.toArray( new Integer[ret.size()] );
}
private void removeProducts(boolean[] temp, int i) {
for (int j = i*i; j < temp.length; j++) {
if(temp[j] && j % i == 0) {
temp[j] = false;
}
}
}
}
You can precompute an array A of size N+1, which stores at A[i] the number of semiprimes less than or equal to i. Then a query p, q can be computed immediately: the number of semiprimes between p and q (inclusive) is A[q] - A[p-1].
This array can be computed efficiently: let P be an array of primes less than or equal to N/2. Then (in java-like pseudocode):
A = new int[N+1]
for (int p : P) {
for (int q : P) {
if (p*q > N || q > p) break;
A[p*q] = 1
}
}
for (int i = 1; i <= N; i++)
A[i] += A[i-1]
This works by marking the semiprimes with a 1 in the array, and then taking a cumulative sum. It runs in better than O(N^2) and worse than O(N) time -- there's about N/2logN primes in P, so the first part is O((N/logN)^2), and the summing-up is O(N). [Note: I guess the first part has better complexity than O((N/log N)^2) because of the early termination of the inner loop, but I've not proved that]. Computing the primes in P is O(N log log N) using the sieve of Erastothenes.
A Python version of this program takes 0.07s to precompute A for N=50000, and to perform 30000 queries. It gets a perfect score (100) when run on codility, and codility reports that it detects the code to be have complexity O(N log(log(N)) + M).
Ruby 100% solution
require 'prime'
require 'set'
def solution(n, p, q)
primes = Prime::EratosthenesGenerator.new.take_while {|i| i <= n/2 }
sqrt = Math.sqrt(n)
semiprimes = primes.each_with_index.inject(Set.new) do |acc, (e,i)|
break acc if e > sqrt.to_i
primes[i..-1].each{ |pr| e*pr > n ? break : acc << e*pr }
acc
end
offsets = semiprimes.sort.each_with_index.inject([]) {|acc,(el,i)| acc[el] = i+1;acc }
p.each_with_index.inject([]) do |acc, (el,i)|
next acc << 0 unless offsets[el..q[i]]
left = offsets[el..q[i]].detect{|a| a}
next acc << 0 unless left
right = offsets[el..q[i]].reverse_each.detect{|a| a}
acc << ((left..right).size)
end
end
My solution uses Sieve of Eratosthenes such that smallest prime factor of number N is stored in the array Factor[N].
Then if Factor[N/Factor[N]] = 0, we have a semi prime number incrementing a sum scan.
The entry r of the returned array will then be:
A[r]=Inclusive_scan[Q[r]]-Inclusive_scan[P[r]-1].
Here the corresponding python code (100% task score):
def solution(N, P, Q):
A=len(P)*[0]
if N<4:
return A
#Minimum prime factor of n stored in Factor[n]
Factor = [0] * (N + 1)
i = 2
while (i * i <= N):
if (Factor[i] == 0):
k = i * i
while (k <= N):
if (Factor[k] == 0):
Factor[k] = i;
k += i
i += 1
#Count semi prime numbers and store
#sum scan in array Incluse_scan
Incluse_scan=[0] * (N + 1)
cnt_semi=0
for k in range(4,N+1):
if Factor[k]!=0:
d=int(k/Factor[k])
if Factor[d]==0:
cnt_semi+=1
Incluse_scan[k]=cnt_semi
#Do the difference of semi prime counters
for r in range(0,len(P)):
if(P[r]<=4):
min_inclusive=0
else:
min_inclusive=P[r]-1
A[r]=Incluse_scan[Q[r]]-Incluse_scan[min_inclusive]
return A
this is my 100% solution in C++. you can find other answers in my github in cpp:
vector<int> getFactArr(int n) {
vector<int> f(n+1, 0);
f[1] = 1;
int i = 2;
while (i * i <= n) {
if (f[i] == 0) {
int k = i * i;
while (k <= n) {
if (f[k] == 0)
f[k] = i;
k+=i;
}
}
i++;
}
return f;
}
vector<int> solution(int N, vector<int> &P, vector<int> &Q) {
vector<int> F = getFactArr(N);
vector<int> prefix_semi_primes(N + 1, 0);
for (int x = 1; x <= N; x++) {
if (F[x] > 0 && F[x / F[x]] == 0)
prefix_semi_primes[x]++;
prefix_semi_primes[x] += prefix_semi_primes[x - 1];
}
const int M = P.size();
vector<int> ans(M, 0);
for (int i = 0; i < M; i++) {
ans[i] = prefix_semi_primes[Q[i]] - prefix_semi_primes[P[i] - 1];
}
return ans;
}
This was an interesting problem. I tried it and got 88% score.
Here is my strategy:
I used Sieve of Eratosthenes for getting a BitSet for primes.
Now I looped over that BitSet and added all the primes in a primeList.
My strategy for finding semi-primes was a bit interesting and I reached to this strategy incrementally.
private static boolean isSemiPrime(int n) {
if(n==1 || n==0 || primeBitSet.get(n))
return false;
int firstFactor = findFirstFactor(n);
if(firstFactor==0 || firstFactor==1)
return false;
return isPrime(n / firstFactor);
}
private static int findFirstFactor(int n) {
for (int i = 0; i < primeList.size(); i++) {
if (n % primeList.get(i) == 0)
return primeList.get(i);
}
// should never be the case
return 0;
}
I'm not very sure why I got 88% score. (What I'm missing)
But the most interesting and worth noting part was the strategy to check whether a given number is Semi-prime or not:
Find the first prime factor of the given number
Then checking that the quotient of the given number and the first-prime-factor is a prime or not.
If it is prime, then the given number is a semi-prime, otherwise the given number is not a semi prime.
Note that I also did a very naive form of book-keeping where I made a cumulative array which stores the total number of semi-primes till index x. One time filling this array and answering each of the query in O(1) is again obvious optimization.
Not related to the solution, but my Task Score was 88%, Correctness 100% and Performance 80%. I'll be happy to hear suggestions and anything that I missed.
Hope this helps. :)
const isSemiPrime = (num) => {
let cnt = 0
for (let i = 2; cnt < 2 && i * i <= num; ++i) {
while (num % i == 0) {
num /= i
++cnt
}
}
if (num > 1)++cnt
return cnt == 2 ? true : false
}
console.log(
[4, 6, 9, 10, 14, 15, 21, 22, 25, 26, 33, 34, 35, 38, 39, 46, 49, 51, 55].filter(isSemiPrime)
.length
)
Here the Javascript version of the solution, but it is 55%:
function solution(N, P, Q) {
function isPrime(num) {
for(var i = 2; i < num; i++)
if(num % i === 0) return false;
return num > 1;
}
const min = Math.min(...P)
const max = Math.max(...Q)
const A = []
for(let i=min;i<max;i++) {
for(let j=min;j<max;j++) {
if (isPrime(i) && isPrime(j)) {
const prod = j * i
if (prod > max) break
if (A.includes(prod)) continue
A.push(j * i)
}
}
}
const result = []
for(let i=0;i<P.length;i++) {
for(let j=P[i];j<=Q[i];j++) {
result[i] = result[i] || 0
if (A.includes(j)) {
result[i]++
}
}
}
return result
}
I would like to mention that the method you use for finding primes is inefficient.
Your code:
private static List<Integer> getPrimes(int max) {
List<Integer> primes = new ArrayList<>(max / 2);
** for (int i = 0; i < max; i++)
** if (isPrime(i))
** primes.add(i);
return primes;
}
private static boolean isPrime(int val) {
if (val <= 1)
return false;
if (val <= 3)
return true;
** for (int i = 2, sqrt = (int)Math.sqrt(val); i <= sqrt; i++)
** if (val % i == 0)
** return false;
return true;
}
I have marked the lines to pay attention to.
I would do something like this:
private static List<Integer> getPrimes(int max) {
List<Integer> primes = new ArrayList<>(max / 2);
primes.add(2);
for (int i = 3; i < max; i++)
if (isPrime(i, primes))
primes.add(i);
return primes;
}
private static boolean isPrime(int val, List<Integer> primes) {
int sqrtv = Math.sqrt(val);
for (int i = 0; i < primes.length(); i++)
{
int prime = primes.get(i);
if (val % primes.get(i) == 0)
{
return false;
} else if (prime > sqrtv) {
return true;
}
}
return true;
}
This plays on the fact that:
the only call to isPrime is from getPrimes. getPrimes will always call val in ascending order.
by the time isPrime is called with the parameter val, getPrimes has already got a list of all primes that are smaller than val.
there's no point in dividing with non-primes when determining primes. If we already know that a number 'a' is not divisible by 2, then why bother with dividing it by 4, 6, 8 or 10? If we know it isn't divisible by 3, then it won't be divisible by 9... so all of the non-prime checks are filtered by using the previously calculated primes only to perform the checking.
Here is my 100% in c++. I'm using prefixSum. Time complexity O(N * log(log(N)) + M).
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
vector<int> solution(int N, vector<int> &P, vector<int> &Q)
{
vector<bool> sieve(N, true);
vector<int> ret;
sieve[0] = sieve[1] = false;
int i = 2;
while (i * i <= N)
{
if (sieve[i])
{
int k = i * i;
while (k <= N)
{
sieve[k] = false;
k += i;
}
}
i++;
}
vector<int> prefixSum(N + 1, 0);
for (int i = 2; i <= sqrt(N); i++)
if (sieve[i])
for (int j = i; j <= N; j++)
{
if (j * i > N)
break;
if (sieve[j])
prefixSum[j * i]++;
}
int carry;
for (unsigned int i = 5; i < prefixSum.size(); i++)
{
carry = prefixSum[i - 1];
prefixSum[i] += carry;
}
for (unsigned int i = 0; i < P.size(); i++)
ret.push_back(prefixSum[Q[i]] - prefixSum[P[i] - 1]);
return ret;
}
A 100% solution broken down. https://app.codility.com/demo/results/trainingGVNHKU-MA5/
Firstly use the sieve of Eratosthenes to workout what is prime.
def get_sieve(n):
# Use the sieve or Eratosthenes to produce an array of primes
# where factor[n] == 0 indicates a prime number
factors = [0] * (n+1)
i=2
i2 = i*i
while (i2 <= n):
if not factors[i]:
k = i2
while k <= n:
if not factors[k]:
factors[k] = i
k += i
i += 1
i2 = i*i
return factors
Next, determine if the number is semi prime. If both its factors are prime its semiprime.
def is_semi_prime(n, factors):
if factors[n]: # Check its not a prime
for r in range(int(n**.5)+1, 1, -1):
if not n%r:
d = n//r
return (not factors[d]) and (not factors[r])
return False
Then scan the range up to N numbers to count slope of increasing semi primes. simply measure the slope within a slice to see how many semi primes occur during that slice.
def solution(N, P, Q):
# produce a slope of increasing semi primes
factors = get_sieve(N)
slope = [0] * (N+1)
for i in range(1, N+1):
slope[i] = slope[i-1] + is_semi_prime(i, factors) # Auto casting!! :-)
# Optimus Prime!
# print(list(enumerate(slope)))
return [slope[Q[j]] - slope[P[j]-1] for j in range(len(P))]
https://github.com/niall-oc/things/blob/master/codility/count_semiprimes.py
and more at
https://github.com/niall-oc/things/blob/master/codility/
I took a slightly different approach. The other efficient solutions in this thread builds a regular Sieve of Eratosthenes (F) with a twist of recording the smallest prime factor in the slot, so semiprimes are those x for which F[x] > 0 and F[x // F[x]] == 0, i.e. dividing by the smallest prime factor yields another prime number.
My approach is a little slower but does not use division, and builds an interesting intermediate: a sieve that computes exactly how many factors make up the prime factorization of the number (and zeros at the primes). For each prime p, I would increment the sieve at position 2p, 3p, 4p,... but also count a factor for p^2, 2p^2, 3p^2..., p^3, 2p^3, 3p^3, 4p^3,... and so forth. The slot for 16 stores the value 4 (prime factorization: 2*2*2*2), because the slot gets hit by visits from 2, 2^2, 2^3 and 2^4.
Then the semiprimes are those positions having exactly 2 prime factors.
After that I build a prefix count of semiprimes with which to answer the queries in constant time.
def solution(N, P, Q):
num_factors = [0] * (N+1)
for i in range(2, N+1):
if num_factors[i] == 0:
# Count visits to multiples of i by adding i each time
add_visit = i+i
while add_visit < N+1:
num_factors[add_visit] += 1
add_visit += i
# But squares of prime count as 2 factors, cubes count as 3 etc,
# so also run visits for multiples of the squares, cubes, etc.
power_prime = i*i
while power_prime < N+1:
visit = power_prime
while visit < N+1:
num_factors[visit] += 1
visit += power_prime
power_prime *= i
semiprime_prefix_count = [0] * (N+1)
for i in range(1, N+1):
semiprime_prefix_count[i] = semiprime_prefix_count[i-1]
if num_factors[i] == 2:
semiprime_prefix_count[i] += 1
results = []
for p, q in zip(P, Q):
results.append(semiprime_prefix_count[q] - semiprime_prefix_count[p-1])
#print(list(zip(range(N+1),num_factors)))
#print(list(zip(range(N+1),semiprime_prefix_count)))
return results
Use the usual sieve to get the prime numbers up to N.
Use the prime number to get semi-prime numbers up to N. You can do this by checking any number for two prime factors.
Create prefix sums to store the number of semi-primes up to a particular index.
Finally, get the semi prime counts by subtracting the numbers at the query end and start.
vector<int> solution(int N, vector<int> &P, vector<int> &Q)
{
vector<int> sieve(N, 0);
for (int prime = 2; prime * prime <= N; ++prime) {
for (int composite = prime * prime; composite <= N; composite += prime) {
if (!sieve[composite - 1]) sieve[composite - 1] = prime;
}
}
vector<int> semi_primes;
for (int i = 3; i < N; ++i) {
const int e = sieve[i];
if (e > 0 && !sieve[i / e]) semi_primes.push_back(i + 1);
}
if (semi_primes.empty()) semi_primes.push_back(0);
vector<int> prefix_sums(N + 1, 0);
for (int i = 1, spi = 0; i <= N; ++i) {
prefix_sums[i] = ((semi_primes[spi] != i) ? spi : ++spi);
}
int M = P.size();
vector<int> semi_prime_counts(M, 0);
for (int i = 0; i < M; ++i) {
semi_prime_counts[i] = prefix_sums[Q[i]] - prefix_sums[P[i] - 1];
}
return semi_prime_counts;
}
function solution(N, P, Q) {
// write your code in JavaScript (Node.js 8.9.4)
let pr =[];let fn =[]
for(var i=2;i<=N;i++){
if(isPrime(i)){
pr.push(i)
}
}
let spr = [],mul,br=0
for(var i=0;i<pr.length;i++){
for(var j=0; j <pr.length;j++){
mul = pr[i] * pr[j];
if(mul <= N) {
spr.push(mul)
}else{
br =1;
break;
}
}
// if(br==1) break;
}
let nm = [];
//let o =0
for(var i=0;i<=N;i++){
if(spr.indexOf(i) >=0){
// ++o
nm.push(1)
}else{
nm.push(0)
}
}
// spr = Array.from(new Set(spr))
// spr.sort((a,b)=> a- b)
let a,b,c
for(var i =0;i<P.length;i++){
// a= findme(P[i],spr)
// b= findme(Q[i],spr)
// a= nm[P[i]]
// b= nm[Q[i]]
c= nm.slice(P[i],Q[i]+1).reduce((a,b)=> a+b)
// c=c <=0 ? 0 : c+1
// fn.push(b - a + 1)
fn.push(c)
}
return fn
}
function findme(a,arr){
for(var i= 0; i< arr.length;i++){
if(a <= arr[i]) return i;
}
}
function isPrime(num){
if (num ===2) return true
for(var i = 2; i < num; i++)
if(num % i === 0) return false;
return num > 1;
}
/**
* https://app.codility.com/demo/results/trainingPBRVXK-28Q/
* time complexity: O(N * log(log N) + M
* space complexity: O(2N + N)
*/
public class CountSemiPrime {
/**
* 2D array for sieving numbers 1..N
* 1 - prime, 2 - semiprime, 3 - composite
*/
public int[][] sieve(int N) {
int[][] sieve = new int[N+1][1];
for (int i=1; i<=N; i++) {
sieve[i][0] = 1; // make prime default
}
for (int i=2; i<= N; i++) {
if (sieve[i][0] == 1) { // if this num is prime, tag its multiples as semi-prime
int next_number = i + i;
while (next_number <= N) {
sieve[next_number][0] = 2;
next_number += i;
}
}
// if this num is semi-prime, tag its multiples as composite
else if (sieve[i][0] == 2) {
int next_number = i + i;
while (next_number <= N) {
sieve[next_number][0] = 3;
next_number += i;
}
}
}
return sieve;
}
public int[] solution(int N, int[] P, int[] Q) {
// first, we need to establish prime and semi-prime numbers from 1 to N, in a sieve
int[][] sieve = sieve(N);
int[] prefix_sum_of_sieve = new int[sieve.length];
for (int i=1; i<sieve.length; i++) {
if (sieve[i][0]==2) {
prefix_sum_of_sieve[i] = prefix_sum_of_sieve[i-1] + 1;
}
else {
prefix_sum_of_sieve[i] = prefix_sum_of_sieve[i-1];
}
}
int[] results = new int[P.length];
// we count the semiprime of N from P and Q, for each P & Q from the prefix sum
for (int i=0; i < P.length; i++) {
results[i] = prefix_sum_of_sieve[Q[i]] - prefix_sum_of_sieve[P[i]-1];
}
return results;
}
}
Hope the explanation / comments are easy to understand.
I have given a sequence of N numbers (4 ≤ N ≤ 150). One index i (0 < i < N) is picked and multiplied with the left and the right number, in other words with i-1 and i+1. Then the i-th number is removed. This is done until the sequence has only two numbers left over. The goal is to find the smallest sum of these products which obviously depends on the order in which the indices are picked.
E.g. for the sequence 44, 45, 5, 39, 15, 22, 10 the smallest sum would be 17775
using the indices in the following order: 1->3->4->5->2 which is the sum:
44*45*5 + 5*39*15 + 5*15*22 + 5*22*10 + 44*5*10 = 9900 + 2925 + 1650 + 1100 + 2200 = 17775
I have found a solution using a recursive function:
public static int smallestSum(List<Integer> values) {
if (values.size() == 3)
return values.get(0) * values.get(1) * values.get(2);
else {
int ret = Integer.MAX_VALUE;
for (int i = 1; i < values.size() - 1; i++) {
List<Integer> copy = new ArrayList<Integer>(values);
copy.remove(i);
int val = smallestSum(copy) + values.get(i - 1) * values.get(i) * values.get(i + 1);
if (val < ret) ret = val;
}
return ret;
}
}
However, this solution is only feasible for small N but not for a bigger amount of numbers. What I am looking for is a way to do this using an iterative Dynamic Programming approach.
The optimal substructure needed for a DP is that, given the identity of the last element removed, the elimination strategy for the elements to the left is independent of the elimination strategy for the elements to the right. Here's a new recursive function (smallestSumA, together with the version from the question and a test harness comparing the two) incorporating this observation:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Foo {
public static void main(String[] args) {
Random r = new Random();
for (int i = 0; i < 10000; i++) {
List<Integer> values = new ArrayList<Integer>();
for (int n = 3 + r.nextInt(8); n > 0; n--) {
values.add(r.nextInt(100));
}
int a = smallestSumA(values, 0, values.size() - 1);
int q = smallestSumQ(values);
if (q != a) {
System.err.println("oops");
System.err.println(q);
System.err.println(a);
System.err.println(values);
}
}
}
public static int smallestSumA(List<Integer> values, int first, int last) {
if (first + 2 > last)
return 0;
int ret = Integer.MAX_VALUE;
for (int i = first + 1; i <= last - 1; i++) {
int val = (smallestSumA(values, first, i)
+ values.get(first) * values.get(i) * values.get(last) + smallestSumA(values, i, last));
if (val < ret)
ret = val;
}
return ret;
}
public static int smallestSumQ(List<Integer> values) {
if (values.size() == 3)
return values.get(0) * values.get(1) * values.get(2);
else {
int ret = Integer.MAX_VALUE;
for (int i = 1; i < values.size() - 1; i++) {
List<Integer> copy = new ArrayList<Integer>(values);
copy.remove(i);
int val = smallestSumQ(copy) + values.get(i - 1) * values.get(i) * values.get(i + 1);
if (val < ret)
ret = val;
}
return ret;
}
}
}
Invoke as smallestSum(values, 0, values.size() - 1).
To get the DP, observe that there are only N choose 2 different settings for first and last, and memoize. The running time is O(N^3).
If anyone is interested in a DP solution, based on David Eisenstat's recursive solution, here is an iterative one using DP (for many big numbers it's useful to replace int's with long's):
public static int smallestSum(List<Integer> values) {
int[][] table = new int[values.size()][values.size()];
for (int i = 2; i < values.size(); i++) {
for (int j = 0; j + i < values.size(); j++) {
int ret = Integer.MAX_VALUE;
for (int k = j + 1; k <= j + i - 1; k++) {
int val = table[j][k] + values.get(j) * values.get(k) * values.get(j + i) + table[k][j + i];
if (val < ret) ret = val;
}
table[j][j + i] = ret;
}
}
return table[0][values.size() - 1];
}
I am trying to write a DP solution for the problem: count total number of sub-sequences possible of an array whose elements' sum is divisible by k.
I have written the following solution. But it is not giving the correct result. Like in the following code snippet, the array is {1, 2, 1} and k = 3. So expected total number of sub sequences divisible by 3 is 2, but the actual result is 3 which is clearly incorrect.
Please point out my mistake.
private int countDP(int[] a, int k)
{
int L = a.length;
int[][] DP = new int[L][k];
for(int i = 0; i < DP.length; i++)
{
for(int j = 0; j < DP[0].length; j++)
DP[i][j] = -1;
}
int res = _countDP(a, k, DP, 0, 0);
return res;
}
private int _countDP(int[] a, int k, int[][] DP, int idx, int m) //Not giving the correct result.
{
if(idx == a.length)
return m == 0 ? 1 : 0;
if(DP[idx][m] != -1)
return DP[idx][m];
int ans = 0;
ans = _countDP(a, k, DP, idx + 1, m);
ans += _countDP(a, k, DP, idx + 1, (m + a[idx]) % k);
return DP[idx][m] = ans;
}
public static void main(String[] args)
{
CountSubnsequences cs = new CountSubnsequences();
int[] a = {1, 2, 1};
int k = 3;
int total1 = cs.countDP(a, k);
System.out.println("Total numeber of sub sequences: " + total1);
}
Let s denote a sequence of length N, and K be a given divisor.
dp[i][j] = the number of subsequences of s[0..i] with remainder equal to j. We will compute dp for all 0 <= i < N and 0 <= j < K.
dp[i][j] = 0 for all (i, j)
dp[0][0] += 1
dp[0][s[0] mod K] += 1
for i = 1 .. N - 1
for j = 0 .. K - 1
dp[i][j] = dp[i - 1][j]
for j = 0 .. K - 1
dp[i][(j + s[i]) mod K] += dp[i - 1][j]
The result is dp[N - 1][0]
Python code of #piotrekg2 solution.
Looks good!
from typing import List
# dp[i][j] = the number of subsequences of length i with remainder equal to j.
def count_subseq(s: List[int],k):
n = len(s)
dp = [0]*k
dp[0] = 1 # i=0, remainder=0, only 1 subseq
for i in range(1,n+1):
dp2 = dp.copy() # copy previous i-length results: results without s[i] in subseq
for j in range(k):
dp2[(j+s[i-1])%k] += dp[j]
dp = dp2
return dp[0]
if __name__ == '__main__':
print(count_subseq([2,3,5,8],5))
print(count_subseq([5,5,5],5))
Faced the same issue. But ended up getting an answer.
The answer returning will be always 1 more than the total possible subsequences. This is because we know that 0 is always being a valid answer. So, if let's say you do not pick any single element from the array, then also the sum=0. So, it considers it as a valid answer and increments our answer by 1. So, to get the actual answer Just decrement the returned value by 1.
int fun(int i,int s)
{
if(i==1){
if(s-a[i]!=0 && (s-a[i])%k==0)
return 1;
else
return 0;}
else{
if((s-a[i])%k==0){
return 1+fun(i-1,s-a[i])+fun(i-1,s);
}
else{
return fun(i-1,s-a[i])+fun(i-1,s);
}
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this 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.
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;
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/