web-dev-qa-db-fra.com

Logique utilisée derrière la manipulation de tableaux de HackerRank

Je ne suis pas en mesure de saisir la logique derrière la solution de ce problème de Hackerrank, https://www.hackerrank.com/challenges/crush/problem

Dans la section de discussion, beaucoup ont également publié leurs solutions, mais je n'arrive pas à comprendre pourquoi cette logique fonctionne.

La solution ci-dessous est tirée de la section de discussion du même problème et a un nombre maximum de votes positifs,

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;


int main() {
    long int N,K,p,q,sum,i,j,max=0,x=0;

    cin>>N>>K;
    long int *a=new long int[N+1]();

    for(i=0;i<K;i++)
    {
        cin>>p>>q>>sum;
        a[p]+=sum;
        if((q+1)<=N) a[q+1]-=sum;
    }

    for(i=1;i<=N;i++)
    {
       x=x+a[i];
       if(max<x) max=x;

    }

    cout<<max;
    return 0;
}

Quelqu'un pourrait-il expliquer la logique derrière la même chose? Merci beaucoup pour votre aide.

16
Vivek kumar

Nous stockons essentiellement l'incrément dans la position de départ et un après le dernier indice de la plage. Pour a b k nous allons augmenter +k pour tous les éléments de l'index [a,b] mais les éléments suivants ne seront pas augmentés. Nous le soustrayons donc, car avec l'incrément précédent, tous les éléments à droite de la plage seront inférieurs de -k. Nous stockons essentiellement toutes les valeurs finales via cet incrément/décrément.

Enfin, nous calculons les éléments à la volée de gauche à droite. Si vous réfléchissez plus profondément, il s'agit simplement de stocker combien un élément est plus grand que l'élément précédent.

Initialement, le tableau sera 0 0 0 0 0.

Après la première opération 1 3 3 à l'origine, les éléments du tableau doivent être 3 3 3 0 0 mais nous le stockons comme ceci

3 0 0 -3 0

Sens

First element is 3 greater than 0.
Second  ->       0 greater than index 1 element.
Third   ->       0 greater than index 2 element
Fourth  ->      -3 greater than index 3 element.
fifth   ->       0 greater than index 4 element.

Après la deuxième opération 2 4 4 à l'origine, le tableau sera 3 7 7 4 0 mais nous le stockons comme ceci 3 4 0 -3 -4. Tout comme je l'ai décrit en détail, gardez à l'esprit cela et pensez de cette façon, vous verrez que nous ne perdons pas d'informations. Nous le stockons simplement d'une manière différente.

Les valeurs finales seront

0+(3) 0+3+(4) 0+3+4+(0) 0+3+4+0+(-3) 0+3+4+0-3+(-4)

3  7    7       4           0  matches with what we got earlier.

Notez comment nous calculons chaque élément. Il suffit d'ajouter l'élément précédent avec la valeur par laquelle l'élément actuel est supérieur.


Notez que cette solution fonctionne car elle n'est interrogée qu'une seule fois. Si elle est interrogée m fois, cette solution ne fonctionne pas car elle expirera. Ensuite, vous devrez creuser plus profondément en utilisant des structures de données avancées comme des arbres de segments et/ou des arbres indexés binaires.

33
user2736738

Ces deux endroits m'ont aidé à mieux comprendre cet algorithme. Prefix_sum_array_and_difference_array
Débordement de pile

Si vous voulez une explication simple et directe: Initial, le tableau est 0 0 0 0 0 cpp after the first operation, 1 2 100 it will become seq1: 100 100 0 0 0 and after second 2 5 100 seq2: 0 100 100 100 100 and after 3 4 100 seq2: 0 0 100 100 0 Mais lorsque nous appliquons un tableau de différences à chaque étape, nous obtiendrons

cpp diff seq of seq1: 100 0 -100 0 0 diff seq of seq2: 0 100 0 0 0 -100 diff seq of seq3: 0 0 100 0 -100

Une propriété importante est la séquence de différence de la somme des séquences est la somme des séquences de différence.

il nous donnera, cpp 100 100 0 0 -100 -100(for clarity purpose only) ou vous pouvez ajouter toutes les séquences en tant que cpp seq1+seq2+seq3 = 100 200 200 200 100 et ensuite trouver la différence seq ou le tableau de différence qui est 100100 0 0-100 puis trouver le tableau de préfixes .

Pourquoi nous ignorons les 100 premiers ??? Lisez le premier article sur le tableau des différences et le tableau de somme des préfixes !!!!

et après cela, faites le préfixe sum cpp 100 200 200 200 100 0 Ignorez le dernier 0 car le dernier index que nous avons considéré est uniquement à des fins de clarté.

donc, ces deux étapes trouvent le tableau des différences pour nous :) cpp a[p]+=sum; if((q+1)<=N) a[q+1]-=sum;

3
Surendra Meena

Je vais essayer d'expliquer ma compréhension de ceci:
Chaque ligne d'entrée décrit essentiellement une séquence, et vous êtes invité à trouver la valeur maximale de la somme de ces séquences.
Par exemple, si N est donné comme 5:
la ligne 2 4 13 décrit la séquence [0, 13, 13, 13, 0]
la ligne 3 5 11 décrit la séquence [0, 0, 11, 11, 11].
Si ce sont les seules lignes, nous obtenons la séquence de résultats à partir de la somme ponctuelle des deux, qui est [0, 13, 24, 24, 11].

Maintenant, une autre façon de décrire les séquences ci-dessus est par les séquences de différence, c'est-à-dire qu'à l'index i nous garderons la différence entre l'élément à l'index i et l'élément à l'index i-1, et nous pouvons obtenir la séquence d'origine par une somme cumulée de la séquence de différence.

Dans le cas des séquences ci-dessus, les séquences de différences sont:
[0, 13, 0, 0, -13] pour la séquence décrite par 2 3 13
[0, 0, 11, 0, 0] pour la séquence décrite par 3 5 11
[0, 13, 11, 0, -13 pour la somme des séquences.

Une propriété importante est la séquence de différence de la somme des séquences est la somme des séquences de différence.

Donc, ce que la solution fait, pour chaque ligne, est de additionner les séquences de différence (ce qui ne nécessite que 2 opérations en raison de la nature des séquences), puis pour trouver le maximum, il faut le total cumulé de la séquence de différence, obtenant ainsi les éléments de la séquence et contient la valeur maximale de ce total cumulé.

Alors que l'exemple que j'ai donné n'a que 2 lignes, cette même idée fonctionne pour n'importe quel nombre de lignes.

J'espère que cela donne une bonne intuition quant à l'idée derrière la solution.

3
M. Aroosi

Le code suivant a fonctionné pour moi en C++. J'ai pris de l'aide en ligne, puis je l'ai codée.

long arrayManipulation(int n, vector<vector<int>> queries) {
  vector<long> resultVector(n);
  long maxVal=0, x=0, i;

  for(int i = 0; i<n ; i++)
  {
      resultVector[i]=0;
  }

  for(i=0; i<queries.size(); i++)
  {
      resultVector[(queries[i][0])-1] += queries[i][2];

      if((queries[i][1]) <= n)
      {
          resultVector[(queries[i][1])] -= queries[i][2];
      }
  }

  for(i=0; i <n; i++)
  {
      x+=resultVector[i];
      if(x>maxVal)
      {
          maxVal=x;
      }
  }

  return maxVal;
}
1
Ankit Sinha
Before solving this problem you must know Prefix Sum Array & Difference array. 

consider below case
a b k
1 5 3
4 8 7
6 9 1 

# if we calculate original array 'A' from this it will be
[3,3,3,10,10,8,8,8,1,0]

# now, lets find out the difference array 'D(A)'
[3,0,0,7,0,-2,0,0,-7,-1]

# follow below steps & calculate the array
A[a] += k
A[b+1] -= k , b+1 < len(A)
you will get [3,0,0,7,0,-2,0,0,-7,-1] which is D(A) itself.

# P(0, D(A)) = A. i.e. calculate prefix sum array of D(A). you will get the original array.
[3,3,3,10,10,8,8,8,1,0]

return max :)
1
ram1993

Il utilise le concept de différence de tableau. C'est un nouveau concept pour ajouter de la valeur à une gamme donnée (i, j, k). i et j spécifient la plage et k est la valeur à ajouter. Il sera très utile de vérifier le lien. https://www.geeksforgeeks.org/difference-array-range-update-query-o1

0
shubham khantwal

au lieu d'ajouter k à tous les éléments d'une plage allant de a à b dans un tableau, accumulez le tableau des différences

Chaque fois que nous ajoutons quelque chose à n'importe quel index dans un tableau et appliquons un algorithme de somme de préfixes, le même élément sera ajouté à chaque élément jusqu'à la fin du tableau.

ex- n = 5, m = 1, a = 2 b = 5 k = 5

    i     0.....1.....2.....3.....4.....5.....6   //take array of size N+2 to avoid index out of bound
  A[i]    0     0     0     0     0     0     0

Ajouter k = 5 à en a = 2

A [a] = A [a] + k // index de départ à partir duquel l'élément k doit être ajouté de façon similaire à a [p] + = sum;

     i    0.....1.....2.....3.....4.....5.....6 
   A[i]   0     0     5     0     0     0     0

maintenant appliquer l'algorithme de somme des préfixes

     i    0.....1.....2.....3.....4.....5.....6 
  A[i]    0     0     5     5     5     5     5

vous pouvez donc voir K = 5 ajouter à tous les éléments jusqu'à la fin après avoir appliqué la somme du préfixe, mais nous n'avons pas à ajouter k jusqu'à la fin. donc pour annuler cet effet, nous devons ajouter -K également après l'index b + 1 de sorte que seulement à partir de la plage [a, b] seulement aura un effet d'addition d'élément K.

A [b + 1] = A [b] -k // pour supprimer l'effet de l'élément k précédemment ajouté après l'index bth. (Identique à [q + 1] - = sum;) c'est pourquoi l'ajout de -k dans l'initiale tableau avec + k.

    i    0.....1.....2.....3.....4.....5.....6 
  A[i]   0     0     5     0     0     0    -5

Maintenant, appliquez la somme de préfixe Array

    i    0.....1.....2.....3.....4.....5.....6 
  A[i]   0     0     5     5     5     5     0

Vous pouvez maintenant voir que K = 5 a été ajouté de a = 2 à b = 5, ce qui était attendu. Ici, nous ne mettons à jour que deux indices pour chaque requête, la complexité sera donc O (1).

Appliquez maintenant le même algorithme en entrée

         # 0.....1.....2.....3.....4.....5.....6    //taken array of size N+2 to avoid index out of bound
5 3      # 0     0     0     0     0     0     0
1 2 100  # 0    100    0   -100    0     0     0       
2 5 100  # 0    100   100  -100    0     0   -100
3 4 100  # 0    100   100    0     0  -100   -100

Pour calculer la somme maximale des préfixes, accumulez le tableau de différences à ???? tout en prenant le préfixe accumulé maximum.

Après avoir effectué toutes les opérations, appliquez maintenant le préfixe sum Array

    i      0.....1.....2.....3.....4.....5.....6 
  A[i]     0     100   200  200   200   100    0

Vous pouvez maintenant parcourir ce tableau pour trouver max qui est 200. parcourir le tableau prendra O(N) temps et la mise à jour des deux indices pour chaque requête prendra O (1) * nombre de requêtes (m)

complexité globale = O (N) + O (M) = O (N + M)

cela signifie = (10 ^ 7 + 10 ^ 5) qui est inférieur à 10 ^ 8 (par seconde)

Remarque: Si vous recherchez tutoriel vidéo , vous devez le vérifier ici pour une explication détaillée.

0
Kanahaiya