web-dev-qa-db-fra.com

java codility Max-Counters

J'ai essayé de résoudre la tâche ci-dessous:

Vous avez N compteurs, réglés initialement à 0, et vous avez deux opérations possibles sur eux:

    increase(X) − counter X is increased by 1,
    max_counter − all counters are set to the maximum value of any counter.

Un tableau non vide à indice A de M entiers est donné. Ce tableau représente des opérations consécutives:

    if A[K] = X, such that 1 ≤ X ≤ N, then operation K is increase(X),
    if A[K] = N + 1 then operation K is max_counter.

Par exemple, étant donné le nombre entier N = 5 et le tableau A tel que:

A[0] = 3
A[1] = 4
A[2] = 4
A[3] = 6
A[4] = 1
A[5] = 4
A[6] = 4

les valeurs des compteurs après chaque opération consécutive seront:

(0, 0, 1, 0, 0)
(0, 0, 1, 1, 0)
(0, 0, 1, 2, 0)
(2, 2, 2, 2, 2)
(3, 2, 2, 2, 2)
(3, 2, 2, 3, 2)
(3, 2, 2, 4, 2)

L'objectif est de calculer la valeur de chaque compteur après toutes les opérations.

struct Results {
  int * C;
  int L;
}; 

Ecrire une fonction:

struct Results solution(int N, int A[], int M); 

que, étant donné un entier N et un tableau A non indexé non vide A constitué de M entiers, retourne une séquence d'entiers représentant les valeurs des compteurs.

La séquence doit être retournée comme:

    a structure Results (in C), or
    a vector of integers (in C++), or
    a record Results (in Pascal), or
    an array of integers (in any other programming language).

Par exemple, étant donné:

A[0] = 3
A[1] = 4
A[2] = 4
A[3] = 6
A[4] = 1
A[5] = 4
A[6] = 4

la fonction devrait renvoyer [3, 2, 2, 4, 2], comme expliqué ci-dessus.

Suppose que:

    N and M are integers within the range [1..100,000];
    each element of array A is an integer within the range [1..N + 1].

Complexité:

    expected worst-case time complexity is O(N+M);
    expected worst-case space complexity is O(N), beyond input storage (not counting the storage required for input arguments).

Les éléments des tableaux d'entrée peuvent être modifiés.

Voici ma solution:

import Java.util.Arrays;

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

        final int condition = N + 1;
        int currentMax = 0;
        int countersArray[] = new int[N];

        for (int iii = 0; iii < A.length; iii++) {
            int currentValue = A[iii];
            if (currentValue == condition) {
                Arrays.fill(countersArray, currentMax);
            } else {
                int position = currentValue - 1;
                int localValue = countersArray[position] + 1;
                countersArray[position] = localValue;

                if (localValue > currentMax) {
                    currentMax = localValue;
                }
            }

        }

        return countersArray;
    }
}

Voici la valorisation du code: https://codility.com/demo/results/demo6AKE5C-EJQ/

Pouvez-vous me donner un indice de ce qui ne va pas avec cette solution?

17
pshemek

Le problème vient avec ce morceau de code:

for (int iii = 0; iii < A.length; iii++) {
     ...
     if (currentValue == condition) {
         Arrays.fill(countersArray, currentMax);
     }
     ...
}

Imaginons que chaque élément du tableau A a été initialisé avec la valeur N+1. Puisque l'appel de fonction Arrays.fill(countersArray, currentMax) a une complexité temporelle de O(N), votre algorithme aura globalement une complexité temporelle O(M * N). Un moyen de résoudre ce problème, je pense, au lieu de mettre à jour explicitement le tableau entier A lorsque l'opération max_counter est appelée, vous pouvez conserver la valeur de la dernière mise à jour en tant que variable. Lorsque la première opération (incrémentation) est appelée, vous voyez simplement si la valeur que vous essayez d’incrémenter est supérieure à last_update. Si c'est le cas, il vous suffit de mettre à jour la valeur avec 1, sinon vous l'initialisez à last_update + 1. Lorsque la deuxième opération est appelée, il suffit de mettre à jour last_update en current_max. Et enfin, lorsque vous avez terminé et essayez de renvoyer les valeurs finales, vous comparez chaque valeur à last_update. S'il est supérieur, vous conservez simplement la valeur, sinon vous retournez last_update

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

        final int condition = N + 1;
        int currentMax = 0;
        int lastUpdate = 0;
        int countersArray[] = new int[N];

        for (int iii = 0; iii < A.length; iii++) {
            int currentValue = A[iii];
            if (currentValue == condition) {
                lastUpdate = currentMax
            } else {
                int position = currentValue - 1;
                if (countersArray[position] < lastUpdate)
                    countersArray[position] = lastUpdate + 1;
                else
                    countersArray[position]++;

                if (countersArray[position] > currentMax) {
                    currentMax = countersArray[position];
                }
            }

        }

        for (int iii = 0; iii < N; iii++)
           if (countersArray[iii] < lastUpdate)
               countersArray[iii] = lastUpdate;

        return countersArray;
    }
}
29
sve

Le problème est que lorsque vous avez beaucoup d'opérations max_counter, vous recevez beaucoup d'appels à Arrays.fill, ce qui ralentit votre solution.

Vous devriez garder une currentMax et une currentMin:

  • Lorsque vous obtenez un max_counter, définissez simplement currentMin = currentMax.
  • Si vous obtenez une autre valeur, appelons-la i:
    • Si la valeur à la position i - 1 est inférieure ou égale à currentMin, définissez-la sur currentMin + 1.
    • Sinon, vous l'incrémentez .

À la fin, parcourez à nouveau le tableau counters et définissez tout ce qui est inférieur à currentMin à currentMin.

8
andredor

Une autre solution que j’ai développée et qui mérite d’être envisagée: http://codility.com/demo/results/demoM658NU-DYR/

4
moda

C'est la solution à 100% de cette question.

// you can also use imports, for example:
// import Java.math.*;
class Solution {
    public int[] solution(int N, int[] A) {
        int counter[] = new int[N];
        int n = A.length;
        int max=-1,current_min=0;

        for(int i=0;i<n;i++){
            if(A[i]>=1 && A[i]<= N){
                if(counter[A[i] - 1] < current_min) counter[A[i] - 1] = current_min;
                counter[A[i] - 1] = counter[A[i] - 1] + 1;
                if(counter[A[i] - 1] > max) max = counter[A[i] - 1];
            }
            else if(A[i] == N+1){
                current_min = max;
            }
        }
        for(int i=0;i<N;i++){
            if(counter[i] < current_min) counter[i] =  current_min;
        }
        return counter;
    }
}
3
Piyush Beli

Voici ma solution C++ qui en a 100 sur la codilité. Le concept est le même que celui expliqué ci-dessus.

int maxx=0;
int lastvalue=0;
void set(vector<int>& A, int N,int X)
    {
        for ( int i=0;i<N;i++)
            if(A[i]<lastvalue)
                A[i]=lastvalue;
    }

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

    vector<int> B(N,0);
    for(unsigned int i=0;i<A.size();i++)
        {
            if(A[i]==N+1)
               lastvalue=maxx;

            else
            {   if(B[A[i]-1]<lastvalue)
                    B[A[i]-1]=lastvalue+1;
                else
                    B[A[i]-1]++;
                if(B[A[i]-1]>maxx)
                    maxx=B[A[i]-1];
            }

        }
        set(B,N,maxx);
    return B;
}
1
piyush121

Voici ma solution en utilisant python 3.6. Le résultat est 100% d’exactitude mais 40% de performance (la plupart d’entre elles étant dues au timeout). Vous ne savez toujours pas comment optimiser ce code, mais j'espère que quelqu'un pourra le trouver utile.

def solution(N, A):
    count = [0]*(N+1)
    for i in range(0,len(A)):
        if A[i] >=1 and A[i] <= N:
            count[A[i]] += 1
        Elif A[i] == (N+1): 
            count = [max(count)] * len(count)
    count.pop(0)
    return count
1
Bagas Adi Pamungkas

100%, O (m + n)

public int[] solution(int N, int[] A) {

    int[] counters = new int[N];
    int maxAIs = 0;
    int minAShouldBe = 0;

    for(int x : A) {
        if(x >= 1 && x <= N) {
            if(counters[x-1] < minAShouldBe) {
                counters[x-1] = minAShouldBe;
            }

            counters[x-1]++;

            if(counters[x-1] > maxAIs) {
                maxAIs = counters[x-1];
            }
        } else if(x == N+1) {
            minAShouldBe = maxAIs;
        }
    }

    for(int i = 0; i < N; i++) {
        if(counters[i] < minAShouldBe) {
            counters[i] = minAShouldBe;
        }
    }

    return counters;
}
0
user5436828
def sample_method(A,N=5):
    initial_array = [0,0,0,0,0]
for i in A:

    if(i>=1):
      if(i<=N):
        initial_array[i-1]+=1
      else:
        for a in range(len(initial_array)):
          initial_array[a]+=1
    print i
    print initial_array
0

voici mon code, mais c'est 88% parce qu'il faut 3,80 secondes pour 10000 éléments au lieu de 2.20

class Solution {

boolean maxCalled;

public int[] solution(int N, int[] A) {

int max =0;
int [] counters = new int [N];
    int temp=0;
    int currentVal = 0;
    for(int i=0;i<A.length;i++){
    currentVal = A[i];
    if(currentVal <=N){
        temp = increas(counters,currentVal);
        if(temp > max){
        max = temp;
        }
    }else{
        if(!maxCalled)
        maxCounter(counters,max);
    }

    }

    return counters;

}


int increas (int [] A, int x){  
 maxCalled = false;
 return ++A[x-1];  
 //return t;
}

void maxCounter (int [] A, int x){
 maxCalled = true;
  for (int i = 0; i < A.length; i++) {
 A[i] = x;
  }

}

}

0
Tamer Saleh

Hera est ma solution Java AC. L'idée est la même que celle expliquée par @Inwvr:

public int[] solution(int N, int[] A) {
        int[] count = new int[N];
        int max = 0;
        int lastUpdate = 0;
        for(int i = 0; i < A.length; i++){
            if(A[i] <= N){
                if(count[A[i]-1] < lastUpdate){
                    count[A[i]-1] = lastUpdate+1;   
                }
                else{
                    count[A[i]-1]++;
                }    
                max = Math.max(max, count[A[i]-1]);
            }
            else{
                lastUpdate = max;   
            }
        }  
        for(int i = 0; i < N; i++){
            if(count[i] < lastUpdate)
                count[i] = lastUpdate;
        }    
        return count;
    }
0
sammy333

Voici ma solution python:

def solution(N, A):
    # write your code in Python 3.6
    RESP = [0] * N
    MAX_OPERATION = N + 1
    current_max = 0
    current_min = 0
    for operation in A:
        if operation != MAX_OPERATION:
            if RESP[operation-1] <= current_min:
                RESP[operation-1] = current_min + 1
            else:
                RESP[operation-1] += 1

            if RESP[operation-1] > current_max:
                current_max = RESP[operation-1]
        else:
            if current_min == current_max:
                current_min += 1
            else:
                current_min = current_max

    for i, val in enumerate(RESP):
        if val < current_min:
            RESP[i] = current_min
    return RESP
0
diofeher

Arrays.fill() invocation dans l'interaction de tableau rend le programme O (N ^ 2)

Ici est une solution possible qui a un runtime O (M + N).

L'idée est - 

  1. Pour la deuxième opération, gardez la trace de la valeur maximale obtenue par incrément. Il s'agit de notre valeur de base jusqu'à l'itération actuelle. Aucune valeur ne peut être inférieure à celle-ci.

  2. Pour la première opération, réinitialiser la valeur sur la valeur de base si nécessaire avant l'incrément.

    public statique int [] solution (int N, int [] A) { int compteurs [] = new int [N];

    int base = 0;
    int cMax = 0;
    
    for (int a : A) {
        if (a > counters.length) {
            base = cMax;
        } else {
            if (counters[a - 1] < base) {
                counters[a - 1] = base;
            }
    
            counters[a - 1]++;
    
            cMax = Math.max(cMax, counters[a - 1]);
        }
    }
    
    for (int i = 0; i < counters.length; i++) {
        if (counters[i] < base) {
            counters[i] = base;
        }
    }
    
    return counters;
    

    }

0
shakhawat

Dans ma solution Java, j'ai mis à jour les valeurs de solution [] uniquement lorsque cela était nécessaire. Et enfin une solution mise à jour [] avec les bonnes valeurs.

public int[] solution(int N, int[] A) {
    int[] solution = new int[N];
    int maxCounter = 0;
    int maxCountersSum = 0;
    for(int a: A) {
        if(a >= 1 && a <= N) {
            if(solution[a - 1] < maxCountersSum)
                solution[a - 1] = maxCountersSum;
            solution[a - 1]++;
            if(solution[a - 1] > maxCounter)
                maxCounter = solution[a - 1];
        }
        if(a == N + 1) {
            maxCountersSum = maxCounter;
        }
    }
    for(int i = 0; i < N; i++) {
        if(solution[i] < maxCountersSum)
            solution[i] = maxCountersSum;
    }

    return solution;
}
0
Andrij

J'ajoute une autre solution Java 100 avec quelques cas de test s'ils sont utiles.

// https://codility.com/demo/results/demoD8J6M5-K3T/ 77
// https://codility.com/demo/results/demoSEJHZS-ZPR/ 100
public class MaxCounters {

  // Some testcases
  // (1,[1,2,3]) = [1]
  // (1,[1]) = [1]
  // (1,[5]) = [0]
  // (1,[1,1,1,2,3]) = 3
  // (2,[1,1,1,2,3,1]) = [4,3]
  // (5, [3, 4, 4, 5, 1, 4, 4]) = (1, 0, 1, 4, 1)
  public int[] solution(int N, int[] A) {
      int length = A.length, maxOfCounter = 0, lastUpdate = 0;
      int applyMax = N + 1;
      int result[] = new int[N];

      for (int i = 0; i < length; ++i ) {
          if(A[i] == applyMax){
              lastUpdate = maxOfCounter;
          } else if (A[i] <= N)  {
              int position = A[i]-1;
              result[position] = result[position] > lastUpdate
                                        ? result[position] + 1 : lastUpdate + 1;
              // updating the max for future use
              if(maxOfCounter <=  result[position]) {
                  maxOfCounter = result[position];
              }
          }
     }
     // updating all the values that are less than the lastUpdate to the max value
     for (int i = 0; i < N; ++i) {
         if(result[i] < lastUpdate) {
             result[i] = lastUpdate;
         }
     }
     return result;
   }
}
0
moxi

Suite à ma solution en Java (100/100).

public boolean isToSum(int value, int N) {
    return value >= 1 && value <= N;
}

public int[] solution(int N, int[] A) {
    int[] res = new int[N];
    int max =0;
    int minValue = 0;

    for (int i=0; i < A.length; i++){
        int value = A[i];
        int pos = value -1;
        if ( isToSum(value, N)) {
            if( res[pos] < minValue) {
                res[pos] = minValue;
            }
            res[pos] += 1;
            if (max < res[pos]) {
                max = res[pos];
            }
        } else {
            minValue = max;
        }
    }

    for (int i=0; i < res.length; i++){
        if ( res[i] < minValue ){
            res[i] = minValue;
        }
    }
    return res;
}
0
Camila Macedo
vector<int> solution(int N, vector<int> &A)
{
    std::vector<int> counters(N);
    auto max = 0;
    auto current = 0;

    for (auto& counter : A)
    {
        if (counter >= 1 && counter <= N)
        {
            if (counters[counter-1] < max)
                counters[counter - 1] = max;

            counters[counter - 1] += 1;

            if (counters[counter - 1] > current)
                current = counters[counter - 1];
        }
        else if (counter > N)
            max = current;

    }

    for (auto&& counter : counters)
        if (counter < max)
            counter = max;

    return counters;
}
0
geekowll

Je viens de recevoir 100 PHP avec l'aide de ce qui précède 

function solution($N, $A) {
    $B = array(0);
    $max = 0;

    foreach($A as $key => $a) {
        $a -= 1;
        if($a == $N) {
            $max = max($B);
        } else {
            if(!isset($B[$a])) {
                $B[$a] = 0;
            }

            if($B[$a] < $max) {
                $B[$a] = $max + 1;
            } else {
                $B[$a] ++;
            }

        }

    }

    for($i=0; $i<$N; $i++) {
        if(!isset($B[$i]) || $B[$i] < $max) {
            $B[$i] = $max;
        }

    }

    return $B;


}
0
Eric Kittell

C'est une autre solution C++ au problème.

La logique est toujours la même. 

  1. Évitez de mettre à compteur maximal tout le compteur à l'instruction deux, car cela porterait la complexité à O (N * M).
  2. Attendez que nous obtenions un autre code d'opération sur un seul compteur. 
  3. À ce stade, l'algorithme se souvient s'il a rencontré un max_counter et définit la valeur du compteur en conséquence.

Voici le code:

vector<int> MaxCounters(int N, vector<int> &A) 
{
    vector<int> n(N, 0);
    int globalMax = 0;
    int localMax = 0;

    for( vector<int>::const_iterator it = A.begin(); it != A.end(); ++it)
    {
        if ( *it >= 1 && *it <= N)
        {
            // this is an increase op.
            int value = *it - 1;
            n[value] = std::max(n[value], localMax ) + 1;
            globalMax = std::max(n[value], globalMax);
        }
        else
        {
            // set max counter op.
            localMax = globalMax;
        }
    }

    for( vector<int>::iterator it = n.begin(); it != n.end(); ++it)
        *it = std::max( *it, localMax );

    return n;
}
0
GrayMouser
  vector<int> solution(int N, vector<int> &A) 
{
    std::vector<int> counter(N, 0); 
    int max = 0;
    int floor = 0;

    for(std::vector<int>::iterator i = A.begin();i != A.end(); i++)
    {
        int index = *i-1;
        if(*i<=N && *i >= 1)
        {
            if(counter[index] < floor)
              counter[index] = floor;
            counter[index] += 1;
            max = std::max(counter[index], max);
        }
        else
        {
            floor = std::max(max, floor);
        }
    }
    for(std::vector<int>::iterator i = counter.begin();i != counter.end(); i++)
    {
       if(*i < floor)
         *i = floor;
    }
    return counter;
}
0
JonathanC

ma solution est: 

public class Solution {  

        public int[] solution(int N, int[] A) {

            int[] counters = new int[N];
            int[] countersLastMaxIndexes = new int[N];
            int maxValue = 0;
            int fixedMaxValue = 0;
            int maxIndex = 0;
            for (int i = 0; i < A.length; i++) {
                if (A[i] <= N) {
                    if (countersLastMaxIndexes[A[i] - 1] != maxIndex) {
                        counters[A[i] - 1] = fixedMaxValue;
                        countersLastMaxIndexes[A[i] - 1] = maxIndex;

                    }
                    counters[A[i] - 1]++;
                    if (counters[A[i] - 1] > maxValue) {
                        maxValue = counters[A[i] - 1];
                    }
                } else {
                    maxIndex = i;
                    fixedMaxValue = maxValue;
                }

            }
            for (int i = 0; i < countersLastMaxIndexes.length; i++) {
                if (countersLastMaxIndexes[i] != maxIndex) {
                    counters[i] = fixedMaxValue;
                    countersLastMaxIndexes[i] = maxIndex;
                }
            }

            return counters;
        }
}
0