web-dev-qa-db-fra.com

Calculer le nombre de paires non ordonnées dans un tableau dont "AND" au niveau du bit est une puissance de 2 dans O(n) ou O (n * log (n))

Comment calculer le nombre de paires non ordonnées dans un tableau dont le bit à bit ET est une puissance de 2. Par exemple, si le tableau est [10,7,2,8,3]. La réponse est 6. Explication (index basé sur 0):

  • a[0]&a[1] = 2
  • a[0]&a[2] = 2
  • a[0]&a[3] = 8
  • a[0]&a[4] = 2
  • a[1]&a[2] = 2
  • a[2]&a[4] = 2

La seule approche qui me vient à l'esprit est la force brute. Comment l'optimiser pour effectuer en O (n) ou O (n * log (n))?

Les contraintes sur la taille du tableau peuvent être au maximum 10^5. Et la valeur de ce tableau peut être jusqu'à 10^12.

Voici le code de force brute que j'ai essayé.

    int ans = 0;
    for (int i = 0; i < a.length; i++) {
        for (int j = i + 1; j < a.length; j++) {
            long and = a[i] & a[j];
            if ((and & (and - 1)) == 0 && and != 0)
                ans++;
        }
    }
    System.out.println(ans);
10
Bhargav kular

Transformez votre tableau de valeurs en un tableau d'ensembles d'index, où chaque ensemble correspond à un bit particulier et contient les index de la valeur de l'ensemble d'origine qui ont le bit défini. Par exemple, votre exemple de tableau A = [10,7,2,8,3] devient B = [{1,4}, {0,1,2,4}, {1}, {0,3}]. Un tableau de taille fixe de vecteurs de bits est une structure de données idéale pour cela, car il rend set union/intersection/setminus relativement facile et efficace.

Une fois que vous avez ce tableau d'ensembles B (prend O(nm) temps où m est la taille de vos entiers en bits), parcourez chaque élément i de A à nouveau, calculant ∑j| Bj∖ i ∖ ⋃kBk: k ≠ j∧i∈Bk|: i∈Bj. Additionnez-les tous ensemble et divisez par 2, et que devrait être le nombre de paires (le "diviser par 2" est parce que cela compte chaque paire deux fois, car ce qu'il compte est le nombre de nombres chacun nombre paires avec). Ne devrait prendre que O (nm2) en supposant que vous comptez les opérations setminus comme O(1) - si vous les comptez comme O (n), alors vous êtes de retour à O (n2), mais au moins votre facteur constant doit être petit si vous avez des bitsets efficaces.

Pseudocode:

foreach A[i] in A:
    foreach bit in A[i]:
        B[bit] += {i}

pairs = 0
foreach A[i] in A:
    foreach B[j] in B:
        if i in B[j]:
            tmp = B[j] - {i}
            foreach B[k] in B:
                if k != j && i in B[k]:
                    tmp -= B[k]
            pairs += |tmp|

return pairs/2
0
Chris Dodd