# What's wrong with this solution for Max Counters codility challenge

## Question:

So I’ve been going through the tests on codility and got bit stuck with the “Max Counters” one (link https://codility.com/demo/take-sample-test/max_counters). My first, and obvious solution was the following one:

``````def solution(N, A):

counters = N * [0];

for a in A:
if 1 <= a <= N:
counters[a - 1] += 1;
elif a == N + 1:
counters = N * [max(counters)];

return counters
``````

which works just fine, but takes too much time, due to the fact that each call to max counters fills an entire array.

So I came up with the following solution which seems to work ok for small inputs, but randomly provides incorrect results for medium and large ones.

``````def solution(N, A):

counters = N * [0];
current_max = 0;
last_update = 0;

for a in A:
if 1 <= a <= N:
counters[a - 1] += 1;

if counters[a - 1] < last_update:
counters[a - 1] = last_update + 1;

if counters[a - 1] > current_max:
current_max = counters[a - 1];

elif a == N + 1:
last_update = current_max;

for i in xrange(len(counters)):
if counters[i] < last_update:
counters[i] = last_update;

return counters
``````

I can’t seem to figure out what’s wrong with it.

Edit: Result – http://codility.com/demo/results/demoQA7BVQ-NQT/

One problem is here:

``````counters[a - 1] += 1
if counters[a - 1] < last_update:
counters[a - 1] = last_update + 1
``````

what if `counters[a - 1]` was `last_update - 1`?

You can take a look at my solution(written in C# though):

``````public static int[] solution(int N, int[] A)
{
// write your code in C# with .NET 2.0
var counters = new int[N];
var defaultValueToInitialize = 0;
var maxElement = 0;

//initializing the counters values, without increasing the N+1 actions
foreach (var num in A)
{
if (num == N + 1)
{
defaultValueToInitialize = maxElement;
counters = new int[N];
}
else
{
counters[num - 1]++;
if (counters[num - 1] + defaultValueToInitialize > maxElement)
maxElement = counters[num - 1] + defaultValueToInitialize;
}

}

//adding the increased default value to each cell

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

return counters;
}
``````

Check this one (python, get’s 100 score):

The secret is not to update all the counters every time you get the instruction to bump them all up to a new minimum value. This incurs an operation involving every counter on every occasion, and is the difference between a ~60% score and a 100% score.

Instead, avoid this hit by keeping track of the current minimum and maximum values; using and updating them for each counter you visit.

Then, after all the instructions are processed, because there may be counters which haven’t been touched with their own personal update since the last update-all instruction, pass over the counters themselves and ensure they are at the minimum value.

``````def solution(N, A):
res = [0] * N
max_val = 0
last_update = 0
n1 = N+1
for i in A:
if i < n1:
if res[i-1] < last_update:
res[i-1] = last_update

res[i-1]+=1

if res[i-1] > max_val:
max_val = res[i-1]
else:
last_update = max_val

for i in xrange(len(res)):
if res[i] < last_update:
res[i] = last_update

return res
``````

http://codility.com/demo/results/demoF3AMPT-FVN/

Consider this 100/100 solution in Ruby:

``````# Algorithm:
#
# * Maintain a maximum value.
# * For each `increase(X)` command update respective counter.
# * For each `max_counter` command save the current max as `set_max` for later use.
# * Once the loop is over, make an adjustment pass to set all values less than `set_max` to `set_max`.
def solution(n, commands)
max = set_max = 0
counters = Array.new(n, 0)

commands.each do |cmd|
if cmd <= n
# This is an `increase(X)` command.
value = [counters[cmd - 1], set_max].max + 1
counters[cmd - 1] = value
max = [value, max].max
else
# This is a `max_counter` command.
# Just update `set_max`.
set_max = max
end
end

# Finalize -- set counters less than `set_max` to `set_max`.
counters.map! {|value| [value, set_max].max}

# Result.
counters
end

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

def test
sets = []
sets << ["1", [1], 1, [1]]
sets << ["sample", [3, 2, 2, 4, 2], 5, [3, 4, 4, 6, 1, 4, 4]]

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

puts "SUCCESS: All tests passed"
end
``````

My python version only scores 66 points as it’s a little too slow for the later tests.

``````def solution(N, A):
counters = [0 for x in range(N)]
for elem in A:
if elem > N:
cmax = max(counters)
counters = [cmax for x in range(N)]
else:
counters[elem-1] += 1
return counters
``````

100/100 solution in C

``````struct Results
solution(int N, int A[], int M)
{
struct Results result;
int *cnts = calloc(N, sizeof(int));
int i = 0, maxcnt = 0, j = 0, lastcnt = 0;
for (i = 0; i < M; i++) {
if (A[i] <= N && A[i] >= 1) {
if (cnts[A[i] - 1] < lastcnt)
cnts[A[i] - 1] = lastcnt + 1;
else
cnts[A[i] - 1] += 1;
if (cnts[A[i] - 1] > maxcnt)
maxcnt = cnts[A[i] - 1];
}
if (A[i] == N + 1)
lastcnt = maxcnt;
}
for (j = 0; j < N; j++) {
if (cnts[j] < lastcnt)
cnts[j] = lastcnt;
}
result.C = cnts;
result.L = N;
return result;
}
``````

MaxCounters solution in C

``````struct Results solution(int N, int A[], int M) {
struct Results result;
// write your code in C90
int i,k=0,max_v=0;

result.C =(int*)(malloc(N*sizeof(int)));
result.L = N;
memset(result.C, 0, N*sizeof(int));

for(i=0;i<M;i++)
{
if (A[i] > N)
max_v=k;
else
{
if(result.C[A[i]-1] < max_v)
result.C[A[i]-1]=max_v;

result.C[A[i]-1]+=1;

if(result.C[A[i]-1] > k)
k=result.C[A[i]-1];
}
}

for(i=0;i<N;i++)
{
if(result.C[i] < max_v)
result.C[i]=max_v;
}

return result;
}
``````

Javascript 100/100

``````function solution(N, A) {

var j, len = A.length, lastBase = 0, max = 0,
counters = [], n1 = N+1;

for(j=0; j<N; j+=1){
counters[j]=0; //initArray
}

for(j=0; j < len; j+=1){
if(A[j]<n1){
if(counters[A[j]-1] < lastBase) {
counters[A[j]-1] = lastBase;
}
counters[A[j]-1] += 1;
if(max < counters[A[j]-1]) {
max = counters[A[j]-1];
}
} else {
lastBase = max;
}
}

for(j=0; j<N; j+=1){
if(counters[j] < lastBase) {
counters[j] = lastBase;
}
}

return counters;

}``````

This is a modified version of @jacoor’s solution with slightly more idiomatic python and variable names and if statement conditions more closely reflecting the problem description.

``````def fast_solution(N, A):
counters = [0] * N
max_counter = 0
last_update = 0

for K,X in enumerate(A): # O(M)
if 1 <= X <= N:
counters[X-1] = max(counters[X-1], last_update)
counters[X-1] += 1
max_counter = max(counters[X-1], max_counter)
elif A[K] == (N + 1):
last_update = max_counter

for i in xrange(N): # O(N)
counters[i] = max(counters[i], last_update)

return counters
``````

https://codility.com/demo/results/demo6KPS7K-87N/

Javascript 100/100

``````function solution(N, A) {
var max = 0,
offset = 0,
counters = Array.apply(null, Array(N)).map(function () {return 0;});

A.forEach(function (d) {
if (d === N + 1) {
offset = max;
}
else {
counters[d-1] = Math.max(offset + 1, counters[d-1] + 1);
max = Math.max(counters[d-1], max);
}
});

counters.map(function (d, i) {
if (d < offset) {
counters[i] = offset;
}
});

return counters;
}
``````

Java solution:

``````public int[] solution(int N, int[] A) {
// write your code in Java SE 8
int[] counter = new int[N];
int maxCounter = 0;
int pos;
int last_max=0;
for (int i = 0; i < A.length; i++) {
if (A[i] <= N) {
pos = A[i];

if (counter[pos - 1] < last_max)
counter[pos - 1] = last_max;
counter[pos - 1] += 1;

if (maxCounter < counter[pos - 1])
maxCounter = counter[pos - 1];
}
else{
last_max=maxCounter;
}
}

for (int i = 0; i < counter.length; i++) {
if (counter[i] < last_max)
counter[i] = last_max;
}
return counter;
}
``````

C++ 100/100

The key is to IGNORE the sample iteration in the problem, it will lead you to a O(m*n) time complexity solution.

``````vector<int> solution(int N, vector<int> &A) {
// write your code in C++11

vector<int> counters(N,0);

int last_reset = 0, max_count = 0;

for( unsigned int a=0; a < A.size(); ++a)
{
int current_int = A.at (a);

if (current_int == (N+1))
{
last_reset = max_count;
}
else
{
unsigned int counter_index = current_int - 1;

if ( counters.at (counter_index) < last_reset)
counters.at (counter_index) = last_reset + 1;
else
++counters.at (counter_index);
if ( counters.at (counter_index) > max_count)
max_count = counters.at (counter_index);
}

}
for( unsigned int n=0; n < counters.size(); ++n)
{
if ( counters.at (n) < last_reset)
counters.at (n) = last_reset;
}
return counters;

}
``````

## C# – a 100/100 solution

``````public int[] solution(int N, int[] A) {
// write your code in C# 6.0 with .NET 4.5 (Mono)
int[] counter = new int[N];
int maxValue = 0;
int minValue = 0;
for(int i=0;i<A.Length;i++)
{
//less than or equal to length N
if(A[i] <= N)
{
if(counter[A[i] - 1] < minValue)
{
counter[A[i] - 1] = minValue;
}
counter[A[i] - 1] += 1;
if(counter[A[i] - 1] > maxValue)
{
maxValue = counter[A[i] - 1];
}
}
else if(A[i] == N+1)
{
minValue = maxValue;
}
}
for(int j=0;j<counter.Length;j++)
{
if(counter[j] < minValue)
{
counter[j] = minValue;
}
}
return counter;
}
``````

here is the shortest solution in Python:

``````def solution(N, A):
out = [0 for _ in range(N)]
for ele in A:
if ele<=N: out[ele-1] += 1
else: out = [max(out) for i in range(len(out))]
return out
``````

# Python 100%

The following solution is simpler and easy to understand from the previous solutions in python where you can use set() to add a possible maximum number each time you find a new possible one. And after that when A[i] is equal to N + 1 you update counters with the max number found in the set and reset it again since the old max would be smaller than the coming ones and not needed. So the line where we clear the set is very important to pass all performance tests

Detected time complexity is:
O(N + M)

``````def solution(N, A):

counters = [0] * N
max_numbers = set()

for i in range(0, len(A)):

if 1 <= A[i] <= N:

index = A[i]-1
counters[index] += 1

elif A[i] == N + 1 and len(max_numbers) > 0:

counters = [max(max_numbers)] * N
max_numbers.clear()

return counters
``````

100% solution with Python–what helped was to keep track of the max in each iteration instead of calculating it each time N+1 appeared

``````def solution(N, A):
counters = [0] * N
all_max = list(set(A))
if len(all_max) == 1 and all_max[0] == N + 1:
return counters

the_max = 0
for i in A:
if i == N + 1:
counters = [the_max] * N
elif i > N + 1:
continue
else:
counters[i-1] += 1
if counters[i-1] > the_max:
the_max = counters[i-1]
return counters
``````

Python

``````from collections import Counter

def solution(N, A):
stop = [i for i in range(len(A)) if A[i] > N]
old = val = 0
for s in stop:
o = A[old:s]
if o:
val += max(Counter(o).values())
old = s + 1
c = [val] * N
start = 0 if not stop else stop[-1] + 1
for i in A[start:]:
c[i-1] += 1
return c
``````
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.