Comptage des inversions dans un tableau

je suis en train de concevoir un algorithme pour faire ce qui suit: donné tableau A[1... n] , pour chaque i < j , trouver toutes les paires d'inversion telle que A[i] > A[j] . J'utilise le tri de fusion et la copie du tableau A Au Tableau B et ensuite je compare les deux tableaux, mais j'ai du mal à voir comment je peux utiliser ceci pour trouver le nombre d'inversions. Tout conseil ou aide serait grandement apprécié.

86
demandé sur Martijn Pieters 2008-12-03 19:07:03

30 réponses

le seul conseil que je pourrais donner à ceci (qui ressemble étrangement à une question de devoir ;) ) est d'abord le faire manuellement avec un petit ensemble de nombres (par exemple 5), et puis noter les étapes que vous avez prises pour résoudre le problème.

Cela devrait vous permettre de trouver une solution générique que vous pouvez utiliser pour écrire le code.

42
répondu Andrew Rollings 2012-10-05 04:19:12

voici donc la solution O(N log n) en java.

long merge(int[] arr, int[] left, int[] right) {
    int i = 0, j = 0, count = 0;
    while (i < left.length || j < right.length) {
        if (i == left.length) {
            arr[i+j] = right[j];
            j++;
        } else if (j == right.length) {
            arr[i+j] = left[i];
            i++;
        } else if (left[i] <= right[j]) {
            arr[i+j] = left[i];
            i++;                
        } else {
            arr[i+j] = right[j];
            count += left.length-i;
            j++;
        }
    }
    return count;
}

long invCount(int[] arr) {
    if (arr.length < 2)
        return 0;

    int m = (arr.length + 1) / 2;
    int left[] = Arrays.copyOfRange(arr, 0, m);
    int right[] = Arrays.copyOfRange(arr, m, arr.length);

    return invCount(left) + invCount(right) + merge(arr, left, right);
}

c'est une sorte de fusion presque normale, toute la magie est cachée dans la fonction de fusion. Notez que pendant le tri algorithme supprimer les inversions. Tandis que la fusion de l'algorithme compte le nombre d'inversions enlevées (trié pourrait dire).

le seul moment où les inversions sont supprimées est lorsque l'algorithme prend l'élément du côté droit d'un tableau et le fusionne avec le tableau principal. Le nombre de les inversions supprimées par cette opération sont le nombre d'éléments restants du tableau de gauche à fusionner. :)

J'espère que c'est assez explicatif.

121
répondu Marek Kirejczyk 2014-08-29 09:48:00

Je l'ai trouvé dans le temps O(N * log n) par la méthode suivante.

  1. fusionner le tableau de tri A et créer une copie (tableau B)
  2. prendre A[1] et trouver sa position dans le tableau B trié via une recherche binaire. Le nombre d'inversions pour cet élément sera un de moins que l'indice de sa position dans B puisque chaque nombre inférieur qui apparaît après le premier élément de A sera une inversion.

    2a. accumuler le nombre d'inversions pour contrer la variable num_inversions.

    2b. Supprimer A[1] du tableau A et aussi de sa position correspondante dans le tableau B

  3. recommencer à partir de l'étape 2 jusqu'à ce qu'il n'y ait plus D'éléments dans A.

voici un exemple d'exécution de cet algorithme. Tableau a Original= (6, 9, 1, 14, 8, 12, 3, 2)

1: fusionner trier et copier dans le tableau B

B = (1, 2, 3, 6, 8, 9, 12, 14)

2: Prenez un[1] et une recherche binaire pour le trouver dans le tableau B

A[1] = 6

B = (1, 2, 3, 6 , 8, 9, 12, 14)

6 est dans la 4ème position du tableau B, donc il y a 3 inversions. Nous savons cela parce que 6 était dans la première position dans le tableau A, donc tout élément de valeur inférieure qui apparaît par la suite dans le tableau A aurait un indice de j > i (puisque i dans ce cas est 1).

2.B: Supprimer A[1] du tableau A et aussi de sa position correspondante dans le tableau B (les éléments en gras sont supprimés).

A = ( 6, 9, 1, 14, 8, 12, 3, 2) = (9, 1, 14, 8, 12, 3, 2)

B = (1, 2, 3, 6, 8, 9, 12, 14) = (1, 2, 3, 8, 9, 12, 14)

3: reprise de l'étape 2 sur les nouveaux tableaux A et B.

A[1] = 9

B = (1, 2, 3, 8, 9, 12, 14)

9 est maintenant dans la 5ème position du tableau B, donc il y a 4 inversions. Nous le savons parce que 9 était dans la première position dans le tableau A, donc tout élément de valeur inférieure qui apparaît par la suite aurait un indice de j > i (puisque i dans ce cas est de Nouveau 1). Supprimer A [1] du tableau A et aussi de sa position correspondante dans le tableau B (les éléments en caractères gras sont supprimés)

A = ( 9 , 1, 14, 8, 12, 3, 2) = (1, 14, 8, 12, 3, 2)

B = (1, 2, 3, 8, 9 , 12, 14) = (1, 2, 3, 8, 12, 14)

continuer dans cette veine nous donnera le nombre total d'inversions pour le tableau a une fois la boucle terminée.

Étape 1 (merge sort) permettrait de prendre en O(n * log n) pour l'exécuter. Étape 2 exécuterait n fois et à chaque exécution effectuerait une recherche binaire qui prend O(log n) pour exécuter pour un total de O(N * log n). La durée totale de fonctionnement serait donc O(n * log n) + O(N * log N) = O (n * log n).

Merci pour votre aide. L'écriture des matrices d'échantillons sur un morceau de papier a vraiment aidé à visualiser le problème.

84
répondu el diablo 2008-12-03 18:36:54

En Python

# O(n log n)

def count_inversion(lst):
    return merge_count_inversion(lst)[1]

def merge_count_inversion(lst):
    if len(lst) <= 1:
        return lst, 0
    middle = int( len(lst) / 2 )
    left, a = merge_count_inversion(lst[:middle])
    right, b = merge_count_inversion(lst[middle:])
    result, c = merge_count_split_inversion(left, right)
    return result, (a + b + c)

def merge_count_split_inversion(left, right):
    result = []
    count = 0
    i, j = 0, 0
    left_len = len(left)
    while i < left_len and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            count += left_len - i
            j += 1
    result += left[i:]
    result += right[j:]
    return result, count        


#test code
input_array_1 = []  #0
input_array_2 = [1] #0
input_array_3 = [1, 5]  #0
input_array_4 = [4, 1] #1
input_array_5 = [4, 1, 2, 3, 9] #3
input_array_6 = [4, 1, 3, 2, 9, 5]  #5
input_array_7 = [4, 1, 3, 2, 9, 1]  #8

print count_inversion(input_array_1)
print count_inversion(input_array_2)
print count_inversion(input_array_3)
print count_inversion(input_array_4)
print count_inversion(input_array_5)
print count_inversion(input_array_6)
print count_inversion(input_array_7)
26
répondu mkso 2013-03-01 05:20:36

je me demande pourquoi personne n'a encore mentionné arbres binaires . Vous pouvez utiliser un pour maintenir des sommes préfixées sur les valeurs de vos éléments de permutation. Ensuite, vous pouvez simplement procéder de droite à gauche et compter pour chaque élément le nombre d'éléments plus petits qu'il à droite:

def count_inversions(a):
  res = 0
  counts = [0]*(len(a)+1)
  rank = { v : i+1 for i, v in enumerate(sorted(a)) }
  for x in reversed(a):
    i = rank[x] - 1
    while i:
      res += counts[i]
      i -= i & -i
    i = rank[x]
    while i <= len(a):
      counts[i] += 1
      i += i & -i
  return res

la complexité est O (N log n), et le facteur constant est très faible.

17
répondu Niklas B. 2016-02-21 18:52:08

j'ai eu une question semblable à celle-ci pour les devoirs en fait. J'ai été restreint qu'il doit avoir O(nlogn) l'efficacité.

j'ai utilisé l'idée que vous avez proposé d'utiliser Mergesort, car il est déjà de l'efficacité correcte. J'ai juste inséré un peu de code dans la fonction de fusion qui était essentiellement: Chaque fois qu'un nombre du tableau de droite est ajouté au tableau de sortie, j'ajoute au nombre total d'inversions, la quantité de nombres restant dans le tableau de gauche.

Cela fait beaucoup de sens pour moi maintenant que j'y ai pensé assez. Vous comptez combien de fois il y a un plus grand nombre qui vient avant n'importe quels nombres.

hth.

13
répondu 2009-02-12 21:47:42

le nombre d'inversions peut être trouvé en analysant le processus de fusion dans merge sort : merge process

lors de la copie d'un élément du second tableau vers le tableau de fusion (le 9 dans cet exemple), il garde sa place relativement aux autres éléments. Lors de la copie d'un élément du premier tableau vers le tableau de fusion (le 5 ici) il est inversé avec tous les éléments restant dans le deuxième tableau (2 inversions avec le 3 et le 4). Donc une petite modification de le tri de fusion peut résoudre le problème dans O(n ln n).

Par exemple, il suffit de découpler les deux lignes # dans le code mergesort python ci-dessous pour avoir le compte.

def merge(l1,l2):
    l = []
    # global count
    while l1 and l2:
        if l1[-1] <= l2[-1]:
            l.append(l2.pop())
        else:
            l.append(l1.pop())
            # count += len(l2)
    l.reverse()
    return l1 + l2 + l

def sort(l): 
    t = len(l) // 2
    return merge(sort(l[:t]), sort(l[t:])) if t > 0 else l

count=0
print(sort([5,1,2,4,9,3]), count)
# [1, 2, 3, 4, 5, 9] 6

EDITION 1

la même tâche peut être réalisée avec une version stable de quick sort, connu pour être légèrement plus rapide:

def part(l):
    pivot=l[-1]
    small,big = [],[]
    count = big_count = 0
    for x in l:
        if x <= pivot:
            small.append(x)
            count += big_count
        else:
            big.append(x)
            big_count += 1
    return count,small,big

def quick_count(l):
    if len(l)<2 : return 0
    count,small,big = part(l)
    small.pop()
    return count + quick_count(small) + quick_count(big)

choisir pivot comme dernier élément, les inversions sont bien comptées, et l'exécution le temps de 40% de mieux que de fusion ci-dessus.

EDIT 2

pour la performance en python, une version numpy & numba:

D'abord la partie numpy, qui utilisent argsort O (n ln n):

def count_inversions(a):
    n = a.size
    counts = np.arange(n) & -np.arange(n)  # The BIT
    ags = a.argsort(kind='mergesort')    
    return  BIT(ags,counts,n)

et la partie numba pour l'efficace BIT approach :

@numba.njit
def BIT(ags,counts,n):
    res = 0        
    for x in ags :
        i = x
        while i:
            res += counts[i]
            i -= i & -i
        i = x+1
        while i < n:
            counts[i] -= 1
            i += i & -i
    return  res  
11
répondu B. M. 2018-01-17 16:08:55

notez que la réponse de Geoffrey Irving est fausse.

Le nombre d'inversions dans un tableau est la moitié de la distance totale des éléments doit être déplacé afin de trier le tableau. Par conséquent, il peut être calculé en triant le tableau, en maintenant la permutation résultante p[i], puis en calculant la somme de abs(p[i]-i)/2. Cela prend du temps O (N log n), ce qui est optimal.

une autre méthode est donnée à http://mathworld.wolfram.com/PermutationInversion.html . Cette méthode est équivalente à la somme de max(0, p[i]-i), qui est égale à la somme de abs(p[i]-i)/2 puisque les éléments de distance totale se déplacent à gauche est égale aux éléments de distance totale se déplacent à droite.

prenons l'exemple de la séquence { 3, 2, 1}. Il y a trois inversions: (3, 2), (3, 1), (2, 1), donc le nombre d'inversion est de 3. Toutefois, selon la méthode Citée, la réponse 2.

8
répondu user1465038 2012-06-19 00:16:49

Check this out: http://www.cs.jhu.edu/~xfliu / 600.363_F03/hw_solution / solution1.pdf

j'espère qu'il vous donnera la bonne réponse.

  • 2-3 Inversion de la partie (d)
  • Il est temps d'exécution est O(nlogn)
5
répondu Hafsa 2012-01-24 13:30:30

le but principal de cette réponse est de comparer les vitesses des différentes versions de Python trouvées ici, mais j'ai aussi quelques contributions personnelles. (FWIW, je viens de découvrir cette question en effectuant une recherche en double).

les vitesses relatives d'exécution des algorithmes implémentés dans CPython peuvent être différentes de ce que l'on attendrait d'une simple analyse des algorithmes, et de l'expérience avec d'autres langues. C'est parce que Python fournit de nombreuses fonctions et méthodes puissantes implémentées en C qui peuvent fonctionner sur des listes et d'autres collections à une vitesse proche de celle que l'on obtiendrait dans un langage entièrement compilé, de sorte que ces opérations s'exécutent beaucoup plus rapidement que des algorithmes équivalents implémentés "manuellement" avec du code Python.

Le Code

qui profite de ces outils peut souvent dépasser théoriquement des algorithmes supérieurs qui essaient de tout faire avec les opérations Python sur des éléments individuels de la collection. Bien sûr, la la quantité réelle de données traitées a également un impact sur ce point. Mais pour des quantités modérées de données, le code qui utilise un algorithme O(n2) tournant à la vitesse C peut facilement battre un algorithme O(N log n) qui fait l'essentiel de son travail avec des opérations Python individuelles.

beaucoup de réponses postées à cette question de comptage d'inversion utilisent un algorithme basé sur mergesort. Théoriquement, c'est une bonne approche, à moins que la taille du tableau soit très petite. Mais Python est intégré TimSort (un algorithme hybride de tri stable, dérivé du tri par fusion et Tri par insertion) fonctionne à la vitesse C, et un port de fusion codé à la main en Python ne peut espérer rivaliser avec lui pour la vitesse.

L'une des solutions les plus intrigantes ici, dans la réponse publiée par Niklas B , utilise le type intégré pour déterminer le classement des éléments de réseau, et un arbre indexé binaire (alias Fenwick tree) pour stocker le les sommes cumulatives nécessaires pour calculer le nombre d'inversions. Dans le processus d'essayer de comprendre cette structure de données et Niklas l'algorithme que j'ai écrit quelques variations de mon propre (posté ci-dessous). Mais j'ai aussi découvert que pour les tailles de liste modérées, c'est en fait plus rapide pour utiliser la fonction sum intégrée à Python que le charmant Arbre de Fenwick.

def count_inversions(a):
    total = 0
    counts = [0] * len(a)
    rank = {v: i for i, v in enumerate(sorted(a))}
    for u in reversed(a):
        i = rank[u]
        total += sum(counts[:i])
        counts[i] += 1
    return total

éventuellement, lorsque la taille de la liste est d'environ 500, l'aspect O (n2) de l'appel sum à l'intérieur de cette boucle for se déchire la tête, et la performance commence à chuter.

Mergesort n'est pas le seul O(nlogn) en quelque sorte, et plusieurs autres peuvent être utilisées pour réaliser l'inversion de comptage. prasadvk's answer utilise un tree sort binaire, cependant son code semble être en C++ ou l'un de ses dérivés. J'ai donc ajouté une version de Python. J'ai utilisé à l'origine une classe pour implémenter les noeuds d'arbre, mais j'ai découvert qu'un dict est sensiblement plus rapide. J'ai finalement utilisé list, qui est encore plus rapide, même si cela rend le code un peu moins lisible.

un bonus de treesort est qu'il est beaucoup plus facile à mettre en œuvre itérativement que mergesort est. Python n'optimise pas la récursion et il a une limite de profondeur de récursion (bien que cela puisse être augmenté si vous vraiment en avez besoin). Et bien sûr, les appels de fonction Python sont relativement lents, donc quand vous essayez d'optimiser pour la vitesse il est bon d'éviter les appels de fonction, lorsqu'elle est possible.

un autre type O(nlogn) est le vénérable type radix. C'est un gros avantage, c'est qu'il ne compare pas les clés entre elles. Son inconvénient est qu'il fonctionne mieux sur les séquences contiguës d'entiers, idéalement une permutation d'entiers dans range(b**m)b est généralement 2. J'ai ajouté quelques versions basées sur le tri radix après avoir essayé de lire en comptant les Inversions, le comptage Orthogonal hors ligne, et les problèmes connexes qui est lié dans calculant le nombre de" inversions "dans une permutation .

pour utiliser radix sort efficacement pour compter les inversions dans une séquence générale seq de longueur n Nous pouvons créer une permutation de range(n) qui a le même nombre d'inversions que seq . Nous pouvons le faire (au pire) O(nlogn) par TimSort. L'astuce consiste à permuter les indices de seq par tri seq . Il est plus facile à expliquer avec un petit exemple.

seq = [15, 14, 11, 12, 10, 13]
b = [t[::-1] for t in enumerate(seq)]
print(b)
b.sort()
print(b)

sortie

[(15, 0), (14, 1), (11, 2), (12, 3), (10, 4), (13, 5)]
[(10, 4), (11, 2), (12, 3), (13, 5), (14, 1), (15, 0)]

en triant les paires (valeur, indice) de seq nous avons permuté les indices de seq avec le même nombre de swaps qui sont nécessaires pour mettre seq dans son ordre original de son ordre trié. Nous pouvons créer cette permutation en triant range(n) avec une fonction clé appropriée:

print(sorted(range(len(seq)), key=lambda k: seq[k]))

sortie

[4, 2, 3, 5, 1, 0]

nous pouvons éviter que lambda en utilisant seq 's .__getitem__ méthode:

sorted(range(len(seq)), key=seq.__getitem__)

ce n'est que légèrement plus rapide, mais nous sommes à la recherche de toutes les améliorations de vitesse que nous pouvons obtenir. ;)


le code ci-dessous exécute timeit tous les essais existants Algorithmes Python sur cette page, plus quelques-uns de mes propres: quelques versions de brute-force O(n2), quelques variations sur l'algorithme de Niklas B, et bien sûr un basé sur mergesort (que j'ai écrit sans faire référence aux réponses existantes). Il dispose également de mon code treesort basé sur la liste, qui est à peu près dérivé du code de prasadvk, et de diverses fonctions basées sur le tri radix, certaines utilisant une stratégie similaire aux approches mergesort, et d'autres utilisant sum ou un arbre de Fenwick.

This programme de mesures, le temps d'exécution de chaque fonction sur une série aléatoire de listes d'entiers; il peut également vérifier que chaque fonction donne les mêmes résultats que les autres, et qu'il ne doit pas modifier la liste d'entrée.

chaque appel timeit donne un vecteur contenant 3 résultats, que je trie. La principale valeur à examiner ici est la valeur minimale, les autres valeurs ne donnent qu'une indication de la fiabilité de cette valeur minimale, comme on l'a vu dans la Note . timeit module docs .

malheureusement, la sortie de ce programme est trop grande pour inclure dans cette réponse, donc je l'affiche dans sa propre réponse (wiki communautaire) .

la sortie est à partir de 3 passages sur mon ancienne machine 2GHz à noyau simple 32 bits fonctionnant en Python 3.6.0 sur une ancienne distro dérivée de Debian. YMMV. Pendant les tests, j'ai éteint mon navigateur Web et je me suis déconnecté de mon routeur pour minimiser l'impact d'autres tâches sur le PROCESSEUR.

le premier essai toutes les fonctions avec des tailles de liste de 5 à 320, avec des tailles de boucle de 4096 à 64 (comme la taille de liste double, la taille de boucle est divisée par deux). Le pool aléatoire utilisé pour construire chaque liste est la moitié de la taille de la liste elle-même, donc nous sommes susceptibles d'obtenir lots de doublons. Certains algorithmes de comptage d'inversion sont plus sensibles aux doublons que d'autres.

La deuxième manche utilise des listes plus grandes: 640 à 10240, et une taille de boucle fixe de 8. Pour gagner du temps, il élimine plusieurs des fonctions les plus lentes des tests. Mes fonctions brute-force O(n2) sont juste way trop lent à ces tailles, et comme mentionné plus tôt, mon code qui utilise sum , qui fait si bien sur les listes petites à modérées, ne peut pas suivre sur les grandes listes.

le dernier tour couvre des tailles de liste de 20480 à 655360, et une taille de boucle fixe de 4, avec le 8 la plus rapide des fonctions. Pour les tailles de liste en dessous de 40.000 ou ainsi le code de Tim Babych est le gagnant clair. Bien fait, Tim! Le code de Niklas B est aussi un bon interprète, bien qu'il soit battu sur les listes plus petites. Le code basé sur la bisection de " python "fonctionne aussi assez bien, bien qu'il semble être un peu plus lent avec d'énormes listes avec beaucoup de doublons, probablement en raison de cette boucle linéaire while qu'il utilise pour enjamber les duplis.

Cependant, pour les très grandes tailles de liste, le les algorithmes basés sur la bisection ne peuvent pas rivaliser avec les vrais algorithmes O(nlogn).

#!/usr/bin/env python3

''' Test speeds of various ways of counting inversions in a list

    The inversion count is a measure of how sorted an array is.
    A pair of items in a are inverted if i < j but a[j] > a[i]

    See /q/counting-inversions-in-an-array-58631/"python"
def solution_python(A):
    B = list(A)
    B.sort()
    inversion_count = 0
    for i in range(len(A)):
        j = binarySearch_python(B, A[i])
        while B[j] == B[j - 1]:
            if j < 1:
                break
            j -= 1
        inversion_count += j
        B.pop(j)
    return inversion_count

def binarySearch_python(alist, item):
    first = 0
    last = len(alist) - 1
    found = False
    while first <= last and not found:
        midpoint = (first + last) // 2
        if alist[midpoint] == item:
            return midpoint
        else:
            if item < alist[midpoint]:
                last = midpoint - 1
            else:
                first = midpoint + 1

# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
# Merge sort version by Zhe Hu
def inv_cnt_ZheHu(a):
    _, count = inv_cnt(a.copy())
    return count

def inv_cnt(a):
    n = len(a)
    if n==1:
        return a, 0
    left = a[0:n//2] # should be smaller
    left, cnt1 = inv_cnt(left)
    right = a[n//2:] # should be larger
    right, cnt2 = inv_cnt(right)

    cnt = 0
    i_left = i_right = i_a = 0
    while i_a < n:
        if (i_right>=len(right)) or (i_left < len(left)
            and left[i_left] <= right[i_right]):
            a[i_a] = left[i_left]
            i_left += 1
        else:
            a[i_a] = right[i_right]
            i_right += 1
            if i_left < len(left):
                cnt += len(left) - i_left
        i_a += 1
    return (a, cnt1 + cnt2 + cnt)

# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
# Merge sort version by noman pouigt
# From https://stackoverflow.com/q/47830098
def reversePairs_nomanpouigt(nums):
    def merge(left, right):
        if not left or not right:
            return (0, left + right)
        #if everything in left is less than right
        if left[len(left)-1] < right[0]:
            return (0, left + right)
        else:
            left_idx, right_idx, count = 0, 0, 0
            merged_output = []

            # check for condition before we merge it
            while left_idx < len(left) and right_idx < len(right):
                #if left[left_idx] > 2 * right[right_idx]:
                if left[left_idx] > right[right_idx]:
                    count += len(left) - left_idx
                    right_idx += 1
                else:
                    left_idx += 1

            #merging the sorted list
            left_idx, right_idx = 0, 0
            while left_idx < len(left) and right_idx < len(right):
                if left[left_idx] > right[right_idx]:
                    merged_output += [right[right_idx]]
                    right_idx += 1
                else:
                    merged_output += [left[left_idx]]
                    left_idx += 1
            if left_idx == len(left):
                merged_output += right[right_idx:]
            else:
                merged_output += left[left_idx:]
        return (count, merged_output)

    def partition(nums):
        count = 0
        if len(nums) == 1 or not nums:
            return (0, nums)
        pivot = len(nums)//2
        left_count, l = partition(nums[:pivot])
        right_count, r = partition(nums[pivot:])
        temp_count, temp_list = merge(l, r)
        return (temp_count + left_count + right_count, temp_list)
    return partition(nums)[0]

# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
# PM 2Ring
def merge_PM2R(seq):
    seq, count = merge_sort_count_PM2R(seq)
    return count

def merge_sort_count_PM2R(seq):
    mid = len(seq) // 2
    if mid == 0:
        return seq, 0
    left, left_total = merge_sort_count_PM2R(seq[:mid])
    right, right_total = merge_sort_count_PM2R(seq[mid:])
    total = left_total + right_total
    result = []
    i = j = 0
    left_len, right_len = len(left), len(right)
    while i < left_len and j < right_len:
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
            total += left_len - i
    result.extend(left[i:])
    result.extend(right[j:])
    return result, total

def rank_sum_PM2R(a):
    total = 0
    counts = [0] * len(a)
    rank = {v: i for i, v in enumerate(sorted(a))}
    for u in reversed(a):
        i = rank[u]
        total += sum(counts[:i])
        counts[i] += 1
    return total

# Fenwick tree functions adapted from C code on Wikipedia
def fen_sum(tree, i):
    ''' Return the sum of the first i elements, 0 through i-1 '''
    total = 0
    while i:
        total += tree[i-1]
        i -= i & -i
    return total

def fen_add(tree, delta, i):
    ''' Add delta to element i and thus 
        to fen_sum(tree, j) for all j > i 
    '''
    size = len(tree)
    while i < size:
        tree[i] += delta
        i += (i+1) & -(i+1)

def fenwick_PM2R(a):
    total = 0
    counts = [0] * len(a)
    rank = {v: i for i, v in enumerate(sorted(a))}
    for u in reversed(a):
        i = rank[u]
        total += fen_sum(counts, i)
        fen_add(counts, 1, i)
    return total

def fenwick_inline_PM2R(a):
    total = 0
    size = len(a)
    counts = [0] * size
    rank = {v: i for i, v in enumerate(sorted(a))}
    for u in reversed(a):
        i = rank[u]
        j = i + 1
        while i:
            total += counts[i]
            i -= i & -i
        while j < size:
            counts[j] += 1
            j += j & -j
    return total

def bruteforce_loops_PM2R(a):
    total = 0
    for i in range(1, len(a)):
        u = a[i]
        for j in range(i):
            if a[j] > u:
                total += 1
    return total

def bruteforce_sum_PM2R(a):
    return sum(1 for i in range(1, len(a)) for j in range(i) if a[j] > a[i])

# Using binary tree counting, derived from C++ code (?) by prasadvk
# https://stackoverflow.com/a/16056139
def ltree_count_PM2R(a):
    total, root = 0, None
    for u in a:
        # Store data in a list-based tree structure
        # [data, count, left_child, right_child]
        p = [u, 0, None, None]
        if root is None:
            root = p
            continue
        q = root
        while True:
            if p[0] < q[0]:
                total += 1 + q[1]
                child = 2
            else:
                q[1] += 1
                child = 3
            if q[child]:
                q = q[child]
            else:
                q[child] = p
                break
    return total

# Counting based on radix sort, recursive version
def radix_partition_rec(a, L):
    if len(a) < 2:
        return 0
    if len(a) == 2:
        return a[1] < a[0]
    left, right = [], []
    count = 0
    for u in a:
        if u & L:
            right.append(u)
        else:
            count += len(right)
            left.append(u)
    L >>= 1
    if L:
        count += radix_partition_rec(left, L) + radix_partition_rec(right, L)
    return count

# The following functions determine swaps using a permutation of 
# range(len(a)) that has the same inversion count as `a`. We can create
# this permutation with `sorted(range(len(a)), key=lambda k: a[k])`
# but `sorted(range(len(a)), key=a.__getitem__)` is a little faster.

# Counting based on radix sort, iterative version
def radix_partition_iter(seq, L):
    count = 0
    parts = [seq]
    while L and parts:
        newparts = []
        for a in parts:
            if len(a) < 2:
                continue
            if len(a) == 2:
                count += a[1] < a[0]
                continue
            left, right = [], []
            for u in a:
                if u & L:
                    right.append(u)
                else:
                    count += len(right)
                    left.append(u)
            if left:
                newparts.append(left)
            if right:
                newparts.append(right)
        parts = newparts
        L >>= 1
    return count

def perm_radixR_PM2R(a):
    size = len(a)
    b = sorted(range(size), key=a.__getitem__)
    n = size.bit_length() - 1
    return radix_partition_rec(b, 1 << n)

def perm_radixI_PM2R(a):
    size = len(a)
    b = sorted(range(size), key=a.__getitem__)
    n = size.bit_length() - 1
    return radix_partition_iter(b, 1 << n)

# Plain sum of the counts of the permutation
def perm_sum_PM2R(a):
    total = 0
    size = len(a)
    counts = [0] * size
    for i in reversed(sorted(range(size), key=a.__getitem__)):
        total += sum(counts[:i])
        counts[i] = 1
    return total

# Fenwick sum of the counts of the permutation
def perm_fenwick_PM2R(a):
    total = 0
    size = len(a)
    counts = [0] * size
    for i in reversed(sorted(range(size), key=a.__getitem__)):
        j = i + 1
        while i:
            total += counts[i]
            i -= i & -i
        while j < size:
            counts[j] += 1
            j += j & -j
    return total

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# All the inversion-counting functions
funcs = (
    solution_TimBabych,
    solutionE_TimBabych,
    solution_python,
    count_inversion_mkso,
    count_inversions_NiklasB,
    merge_count_BM,
    inv_cnt_ZheHu,
    reversePairs_nomanpouigt,
    fenwick_PM2R,
    fenwick_inline_PM2R,
    merge_PM2R,
    rank_sum_PM2R,
    bruteforce_loops_PM2R,
    bruteforce_sum_PM2R,
    ltree_count_PM2R,
    perm_radixR_PM2R,
    perm_radixI_PM2R,
    perm_sum_PM2R,
    perm_fenwick_PM2R,
)

def time_test(seq, loops, verify=False):
    orig = seq
    timings = []
    for func in funcs:
        seq = orig.copy()
        value = func(seq) if verify else None
        t = Timer(lambda: func(seq))
        result = sorted(t.repeat(3, loops))
        timings.append((result, func.__name__, value))
        assert seq==orig, 'Sequence altered by {}!'.format(func.__name__)
    first = timings[0][-1]
    timings.sort()
    for result, name, value in timings:
        result = ', '.join([format(u, '.5f') for u in result])
        print('{:24} : {}'.format(name, result))

    if verify:
        # Check that all results are identical
        bad = ['%s: %d' % (name, value)
            for _, name, value in timings if value != first]
        if bad:
            print('ERROR. Value: {}, bad: {}'.format(first, ', '.join(bad)))
        else:
            print('Value: {}'.format(first))
    print()

#Run the tests
size, loops = 5, 1 << 12
verify = True
for _ in range(7):
    hi = size // 2
    print('Size = {}, hi = {}, {} loops'.format(size, hi, loops))
    seq = [randrange(hi) for _ in range(size)]
    time_test(seq, loops, verify)
    loops >>= 1
    size <<= 1

#size, loops = 640, 8
#verify = False
#for _ in range(5):
    #hi = size // 2
    #print('Size = {}, hi = {}, {} loops'.format(size, hi, loops))
    #seq = [randrange(hi) for _ in range(size)]
    #time_test(seq, loops, verify)
    #size <<= 1

#size, loops = 163840, 4
#verify = False
#for _ in range(3):
    #hi = size // 2
    #print('Size = {}, hi = {}, {} loops'.format(size, hi, loops))
    #seq = [randrange(hi) for _ in range(size)]
    #time_test(seq, loops, verify)
    #size <<= 1

Veuillez voir ici pour la sortie de

5
répondu PM 2Ring 2017-12-21 18:50:56

Voici une solution possible avec variation de l'arbre binaire. Il ajoute un champ appelé rightSubTreeSize à chaque noeud d'arbre. Continuer à insérer le nombre dans l'arbre binaire dans l'ordre où ils apparaissent dans le tableau. Si le nombre va lhs de noeud le compte d'inversion pour cet élément serait (1 + rightSubTreeSize). Puisque tous ces éléments sont plus grands que l'élément courant et ils seraient apparus plus tôt dans le tableau. Si l'élément va à rhs d'un noeud, il suffit d'augmenter sa rightSubTreeSize. Voici le code.

Node { 
    int data;
    Node* left, *right;
    int rightSubTreeSize;

    Node(int data) { 
        rightSubTreeSize = 0;
    }   
};

Node* root = null;
int totCnt = 0;
for(i = 0; i < n; ++i) { 
    Node* p = new Node(a[i]);
    if(root == null) { 
        root = p;
        continue;
    } 

    Node* q = root;
    int curCnt = 0;
    while(q) { 
        if(p->data <= q->data) { 
            curCnt += 1 + q->rightSubTreeSize;
            if(q->left) { 
                q = q->left;
            } else { 
                q->left = p;
                break;
            }
        } else { 
            q->rightSubTreeSize++;
            if(q->right) { 
                q = q->right;
            } else { 
                q->right = p;
                break;
            }
        }
    }

    totCnt += curCnt;
  }
  return totCnt;
4
répondu prasadvk 2013-04-17 09:15:18
public static int mergeSort(int[] a, int p, int r)
{
    int countInversion = 0;
    if(p < r)
    {
        int q = (p + r)/2;
        countInversion = mergeSort(a, p, q);
        countInversion += mergeSort(a, q+1, r);
        countInversion += merge(a, p, q, r);
    }
    return countInversion;
}

public static int merge(int[] a, int p, int q, int r)
{
    //p=0, q=1, r=3
    int countingInversion = 0;
    int n1 = q-p+1;
    int n2 = r-q;
    int[] temp1 = new int[n1+1];
    int[] temp2 = new int[n2+1];
    for(int i=0; i<n1; i++) temp1[i] = a[p+i];
    for(int i=0; i<n2; i++) temp2[i] = a[q+1+i];

    temp1[n1] = Integer.MAX_VALUE;
    temp2[n2] = Integer.MAX_VALUE;
    int i = 0, j = 0;

    for(int k=p; k<=r; k++)
    {
        if(temp1[i] <= temp2[j])
        {
            a[k] = temp1[i];
            i++;
        }
        else
        {
            a[k] = temp2[j];
            j++;
            countingInversion=countingInversion+(n1-i); 
        }
    }
    return countingInversion;
}
public static void main(String[] args)
{
    int[] a = {1, 20, 6, 4, 5};
    int countInversion = mergeSort(a, 0, a.length-1);
    System.out.println(countInversion);
}
4
répondu Trying 2013-07-24 07:18:42

Puisqu'il s'agit d'une vieille question, je vais donner ma réponse en C.

#include <stdio.h>

int count = 0;
int inversions(int a[], int len);
void mergesort(int a[], int left, int right);
void merge(int a[], int left, int mid, int right);

int main() {
  int a[] = { 1, 5, 2, 4, 0 };
  printf("%d\n", inversions(a, 5));
}

int inversions(int a[], int len) {
  mergesort(a, 0, len - 1);
  return count;
}

void mergesort(int a[], int left, int right) {
  if (left < right) {
     int mid = (left + right) / 2;
     mergesort(a, left, mid);
     mergesort(a, mid + 1, right);
     merge(a, left, mid, right);
  }
}

void merge(int a[], int left, int mid, int right) {
  int i = left;
  int j = mid + 1;
  int k = 0;
  int b[right - left + 1];
  while (i <= mid && j <= right) {
     if (a[i] <= a[j]) {
       b[k++] = a[i++];
     } else {
       printf("right element: %d\n", a[j]);
       count += (mid - i + 1);
       printf("new count: %d\n", count);
       b[k++] = a[j++];
     }
  }
  while (i <= mid)
    b[k++] = a[i++];
  while (j <= right)
    b[k++] = a[j++];
  for (i = left, k = 0; i <= right; i++, k++) {
    a[i] = b[k];
  }
}
3
répondu mbreining 2012-11-29 21:27:31

Voici c++ solution

/**
*array sorting needed to verify if first arrays n'th element is greater than sencond arrays
*some element then all elements following n will do the same
*/
#include<stdio.h>
#include<iostream>
using namespace std;
int countInversions(int array[],int size);
int merge(int arr1[],int size1,int arr2[],int size2,int[]);
int main()
{
    int array[] = {2, 4, 1, 3, 5};
    int size = sizeof(array) / sizeof(array[0]);
    int x = countInversions(array,size);
    printf("number of inversions = %d",x);
}

int countInversions(int array[],int size)
{
    if(size > 1 )
    {
    int mid = size / 2;
    int count1 = countInversions(array,mid);
    int count2 = countInversions(array+mid,size-mid);
    int temp[size];
    int count3 = merge(array,mid,array+mid,size-mid,temp);
    for(int x =0;x<size ;x++)
    {
        array[x] = temp[x];
    }
    return count1 + count2 + count3;
    }else{
        return 0;
    }
}

int merge(int arr1[],int size1,int arr2[],int size2,int temp[])
{
    int count  = 0;
    int a = 0;
    int b = 0;
    int c = 0;
    while(a < size1 && b < size2)
    {
        if(arr1[a] < arr2[b])
        {
            temp[c] = arr1[a];
            c++;
            a++;
        }else{
            temp[c] = arr2[b];
            b++;
            c++;
            count = count + size1 -a;
        }
    }

    while(a < size1)
    {
        temp[c] = arr1[a];
        c++;a++;
    }

while(b < size2)
    {
        temp[c] = arr2[b];
        c++;b++;
    }

    return count;
}
3
répondu Dheeraj Sachan 2014-11-25 18:00:12

voici un code C pour les inversions de comptage

#include <stdio.h>
#include <stdlib.h>

int  _mergeSort(int arr[], int temp[], int left, int right);
int merge(int arr[], int temp[], int left, int mid, int right);

/* This function sorts the input array and returns the
   number of inversions in the array */
int mergeSort(int arr[], int array_size)
{
    int *temp = (int *)malloc(sizeof(int)*array_size);
    return _mergeSort(arr, temp, 0, array_size - 1);
}

/* An auxiliary recursive function that sorts the input array and
  returns the number of inversions in the array. */
int _mergeSort(int arr[], int temp[], int left, int right)
{
  int mid, inv_count = 0;
  if (right > left)
  {
    /* Divide the array into two parts and call _mergeSortAndCountInv()
       for each of the parts */
    mid = (right + left)/2;

    /* Inversion count will be sum of inversions in left-part, right-part
      and number of inversions in merging */
    inv_count  = _mergeSort(arr, temp, left, mid);
    inv_count += _mergeSort(arr, temp, mid+1, right);

    /*Merge the two parts*/
    inv_count += merge(arr, temp, left, mid+1, right);
  }
  return inv_count;
}

/* This funt merges two sorted arrays and returns inversion count in
   the arrays.*/
int merge(int arr[], int temp[], int left, int mid, int right)
{
  int i, j, k;
  int inv_count = 0;

  i = left; /* i is index for left subarray*/
  j = mid;  /* i is index for right subarray*/
  k = left; /* i is index for resultant merged subarray*/
  while ((i <= mid - 1) && (j <= right))
  {
    if (arr[i] <= arr[j])
    {
      temp[k++] = arr[i++];
    }
    else
    {
      temp[k++] = arr[j++];

     /*this is tricky -- see above explanation/diagram for merge()*/
      inv_count = inv_count + (mid - i);
    }
  }

  /* Copy the remaining elements of left subarray
   (if there are any) to temp*/
  while (i <= mid - 1)
    temp[k++] = arr[i++];

  /* Copy the remaining elements of right subarray
   (if there are any) to temp*/
  while (j <= right)
    temp[k++] = arr[j++];

  /*Copy back the merged elements to original array*/
  for (i=left; i <= right; i++)
    arr[i] = temp[i];

  return inv_count;
}

/* Driver progra to test above functions */
int main(int argv, char** args)
{
  int arr[] = {1, 20, 6, 4, 5};
  printf(" Number of inversions are %d \n", mergeSort(arr, 5));
  getchar();
  return 0;
}

une explication a été donnée en détail ici: http://www.geeksforgeeks.org/counting-inversions /

2
répondu banarun 2013-03-09 15:46:45

Ici est O(n*log(n)) perl mise en œuvre:

sub sort_and_count {
    my ($arr, $n) = @_;
    return ($arr, 0) unless $n > 1;

    my $mid = $n % 2 == 1 ? ($n-1)/2 : $n/2;
    my @left = @$arr[0..$mid-1];
    my @right = @$arr[$mid..$n-1];

    my ($sleft, $x) = sort_and_count( \@left, $mid );
    my ($sright, $y) = sort_and_count( \@right, $n-$mid);
    my ($merged, $z) = merge_and_countsplitinv( $sleft, $sright, $n );

    return ($merged, $x+$y+$z);
}

sub merge_and_countsplitinv {
    my ($left, $right, $n) = @_;

    my ($l_c, $r_c) = ($#$left+1, $#$right+1);
    my ($i, $j) = (0, 0);
    my @merged;
    my $inv = 0;

    for my $k (0..$n-1) {
        if ($i<$l_c && $j<$r_c) {
            if ( $left->[$i] < $right->[$j]) {
                push @merged, $left->[$i];
                $i+=1;
            } else {
                push @merged, $right->[$j];
                $j+=1;
                $inv += $l_c - $i;
            }
        } else {
            if ($i>=$l_c) {
                push @merged, @$right[ $j..$#$right ];
            } else {
                push @merged, @$left[ $i..$#$left ];
            }
            last;
        }
    }

    return (\@merged, $inv);
}
2
répondu Omid 2015-01-29 19:03:04

la réponse facile O (N^2) est d'utiliser emboîtés pour-boucles et incrémenter un compteur pour chaque inversion

int counter = 0;

for(int i = 0; i < n - 1; i++)
{
    for(int j = i+1; j < n; j++)
    {
        if( A[i] > A[j] )
        {
            counter++;
        }
    }
}

return counter;

maintenant je suppose que vous voulez une solution plus efficace, je vais y réfléchir.

1
répondu mbillard 2008-12-03 16:31:38

une solution possible en C++ satisfaisant à l'exigence O(N*log(N)) de complexité temporelle serait la suivante.

#include <algorithm>

vector<int> merge(vector<int>left, vector<int>right, int &counter)
{

    vector<int> result;

    vector<int>::iterator it_l=left.begin();
    vector<int>::iterator it_r=right.begin();

    int index_left=0;

    while(it_l!=left.end() || it_r!=right.end())
    {

        // the following is true if we are finished with the left vector 
        // OR if the value in the right vector is the smaller one.

        if(it_l==left.end() || (it_r!=right.end() && *it_r<*it_l) )
        {
            result.push_back(*it_r);
            it_r++;

            // increase inversion counter
            counter+=left.size()-index_left;
        }
        else
        {
            result.push_back(*it_l);
            it_l++;
            index_left++;

        }
    }

    return result;
}

vector<int> merge_sort_and_count(vector<int> A, int &counter)
{

    int N=A.size();
    if(N==1)return A;

    vector<int> left(A.begin(),A.begin()+N/2);
    vector<int> right(A.begin()+N/2,A.end());

    left=merge_sort_and_count(left,counter);
    right=merge_sort_and_count(right,counter);


    return merge(left, right, counter);

}

il diffère d'un tri régulier de fusion seulement par le compteur.

1
répondu oo_miguel 2013-09-16 01:29:07

O(n log n), O(n) de l'espace de solution en java.

Un mergesort, avec un réglage de préserver le nombre d'inversions effectuées au cours de l'étape de fusion et publipostage. (pour un mergesort bien expliqué jeter un oeil à http://www.vogella.com/tutorials/JavaAlgorithmsMergesort/article.html )

puisque mergesort peut être fait en place, la complexité de l'espace peut être améliorée à O(1).

lors de l'utilisation de ce type, le les inversions se produisent seulement dans l'étape de fusion et seulement quand nous devons mettre un élément de la deuxième partie avant les éléments de la première moitié, par exemple

  • 0 5 10 15

fusionné avec

  • 1 6 22

nous avons 3 + 2 + 0 = 5 inversions:

  • 1 avec {5, 10, 15}
  • 6 avec {10, 15}
  • 22 avec {}

après avoir fait les 5 inversions, notre nouvelle liste fusionnée est 0, 1, 5, 6, 10, 15, 22

il y a une tâche de démonstration sur la Codilité appelée ArrayInversionCount, où vous pouvez tester votre solution.

    public class FindInversions {

    public static int solution(int[] input) {
        if (input == null)
            return 0;
        int[] helper = new int[input.length];
        return mergeSort(0, input.length - 1, input, helper);
    }

    public static int mergeSort(int low, int high, int[] input, int[] helper) {
        int inversionCount = 0;
        if (low < high) {
            int medium = low + (high - low) / 2;
            inversionCount += mergeSort(low, medium, input, helper);
            inversionCount += mergeSort(medium + 1, high, input, helper);
            inversionCount += merge(low, medium, high, input, helper);
        }
        return inversionCount;
    }

    public static int merge(int low, int medium, int high, int[] input, int[] helper) {
        int inversionCount = 0;

        for (int i = low; i <= high; i++)
            helper[i] = input[i];

        int i = low;
        int j = medium + 1;
        int k = low;

        while (i <= medium && j <= high) {
            if (helper[i] <= helper[j]) {
                input[k] = helper[i];
                i++;
            } else {
                input[k] = helper[j];
                // the number of elements in the first half which the j element needs to jump over.
                // there is an inversion between each of those elements and j.
                inversionCount += (medium + 1 - i);
                j++;
            }
            k++;
        }

        // finish writing back in the input the elements from the first part
        while (i <= medium) {
            input[k] = helper[i];
            i++;
            k++;
        }
        return inversionCount;
    }

}
1
répondu Andrey Petrov 2014-07-12 18:25:15

ma réponse en Python:

1 - triez d'abord le tableau et faites-en une copie. Dans mon programme, B représente le tableau trié. 2 - effectuer une Itération sur le tableau d'origine (non triées), et de trouver l'indice de l'élément sur la liste triée. Notez également l'indice de l'élément. 3 - assurez-vous que l'élément n'a pas de doublons, si elle a ensuite, vous devez modifier la valeur de votre index par -1. La condition de mon programme est exactement de faire ça. 4 - continuer à compter les inversion qui va votre valeur d'index, et supprimer l'élément une fois que vous avez calculé son inversion.

def binarySearch(alist, item):
    first = 0
    last = len(alist) - 1
    found = False

    while first <= last and not found:
        midpoint = (first + last)//2
        if alist[midpoint] == item:
            return midpoint
        else:
            if item < alist[midpoint]:
                last = midpoint - 1
            else:
                first = midpoint + 1

def solution(A):

    B = list(A)
    B.sort()
    inversion_count = 0
    for i in range(len(A)):
        j = binarySearch(B, A[i])
        while B[j] == B[j - 1]:
            if j < 1:
                break
            j -= 1

        inversion_count += j
        B.pop(j)

    if inversion_count > 1000000000:
        return -1
    else:
        return inversion_count

print solution([4, 10, 11, 1, 3, 9, 10])
1
répondu python 2015-11-03 17:39:07

Eh bien, j'ai une solution différente, mais je crains que cela ne fonctionne que pour des éléments de réseau distincts.

//Code
#include <bits/stdc++.h>
using namespace std;

int main()
{
    int i,n;
    cin >> n;
    int arr[n],inv[n];
    for(i=0;i<n;i++){
        cin >> arr[i];
    }
    vector<int> v;
    v.push_back(arr[n-1]);
    inv[n-1]=0;
    for(i=n-2;i>=0;i--){
        auto it = lower_bound(v.begin(),v.end(),arr[i]); 
        //calculating least element in vector v which is greater than arr[i]
        inv[i]=it-v.begin();
        //calculating distance from starting of vector
        v.insert(it,arr[i]);
        //inserting that element into vector v
    }
    for(i=0;i<n;i++){
        cout << inv[i] << " ";
    }
    cout << endl;
    return 0;
}

Pour expliquer mon code nous continuons à ajouter des éléments à partir de la fin du Tableau.Pour tout élément de tableau entrant, nous trouvons l'indice du premier élément du vecteur v qui est plus grand que notre élément entrant et assignons cette valeur au compte d'inversion de l'indice de l'élément entrant.Après cela, nous insérons cet élément dans le vecteur v at c'est la bonne position pour que le vecteur v reste en ordre.

//INPUT     
4
2 1 4 3

//OUTPUT    
1 0 1 0

//To calculate total inversion count just add up all the elements in output array
1
répondu Varun Garg 2016-06-15 01:23:20

une autre solution Python, courte. Utilise le module bisect intégré, qui fournit des fonctions pour insérer l'élément dans sa place dans le tableau trié et pour trouver l'index de l'élément dans le tableau trié.

l'idée est de stocker les éléments restants de n-th dans un tel tableau, ce qui nous permettrait de trouver facilement le nombre d'entre eux plus grand que n-th.

import bisect
def solution(A):
    sorted_left = []
    res = 0
    for i in xrange(1, len(A)):
        bisect.insort_left(sorted_left, A[i-1])
        # i is also the length of sorted_left
        res += (i - bisect.bisect(sorted_left, A[i]))
    return res
1
répondu Tim Babych 2017-12-18 21:39:20

Cette réponse contient les résultats de la timeit tests produits par le code dans mon principale réponse . Reportez-vous à la réponse pour plus de détails!

count_inversions speed test results

Size = 5, hi = 2, 4096 loops
ltree_count_PM2R         : 0.04871, 0.04872, 0.04876
bruteforce_loops_PM2R    : 0.05696, 0.05700, 0.05776
solution_TimBabych       : 0.05760, 0.05822, 0.05943
solutionE_TimBabych      : 0.06642, 0.06704, 0.06760
bruteforce_sum_PM2R      : 0.07523, 0.07545, 0.07563
perm_sum_PM2R            : 0.09873, 0.09875, 0.09935
rank_sum_PM2R            : 0.10449, 0.10463, 0.10468
solution_python          : 0.13034, 0.13061, 0.13221
fenwick_inline_PM2R      : 0.14323, 0.14610, 0.18802
perm_radixR_PM2R         : 0.15146, 0.15203, 0.15235
merge_count_BM           : 0.16179, 0.16267, 0.16467
perm_radixI_PM2R         : 0.16200, 0.16202, 0.16768
perm_fenwick_PM2R        : 0.16887, 0.16920, 0.17075
merge_PM2R               : 0.18262, 0.18271, 0.18418
count_inversions_NiklasB : 0.19183, 0.19279, 0.20388
count_inversion_mkso     : 0.20060, 0.20141, 0.20398
inv_cnt_ZheHu            : 0.20815, 0.20841, 0.20906
fenwick_PM2R             : 0.22109, 0.22137, 0.22379
reversePairs_nomanpouigt : 0.29620, 0.29689, 0.30293
Value: 5

Size = 10, hi = 5, 2048 loops
solution_TimBabych       : 0.05954, 0.05989, 0.05991
solutionE_TimBabych      : 0.05970, 0.05972, 0.05998
perm_sum_PM2R            : 0.07517, 0.07519, 0.07520
ltree_count_PM2R         : 0.07672, 0.07677, 0.07684
bruteforce_loops_PM2R    : 0.07719, 0.07724, 0.07817
rank_sum_PM2R            : 0.08587, 0.08823, 0.08864
bruteforce_sum_PM2R      : 0.09470, 0.09472, 0.09484
solution_python          : 0.13126, 0.13154, 0.13185
perm_radixR_PM2R         : 0.14239, 0.14320, 0.14474
perm_radixI_PM2R         : 0.14632, 0.14669, 0.14679
fenwick_inline_PM2R      : 0.16796, 0.16831, 0.17030
perm_fenwick_PM2R        : 0.18189, 0.18212, 0.18638
merge_count_BM           : 0.19816, 0.19870, 0.19948
count_inversions_NiklasB : 0.21807, 0.22031, 0.22215
merge_PM2R               : 0.22037, 0.22048, 0.26106
fenwick_PM2R             : 0.24290, 0.24314, 0.24744
count_inversion_mkso     : 0.24895, 0.24899, 0.25205
inv_cnt_ZheHu            : 0.26253, 0.26259, 0.26590
reversePairs_nomanpouigt : 0.35711, 0.35762, 0.35973
Value: 20

Size = 20, hi = 10, 1024 loops
solutionE_TimBabych      : 0.05687, 0.05696, 0.05720
solution_TimBabych       : 0.06126, 0.06151, 0.06168
perm_sum_PM2R            : 0.06875, 0.06906, 0.07054
rank_sum_PM2R            : 0.07988, 0.07995, 0.08002
ltree_count_PM2R         : 0.11232, 0.11239, 0.11257
bruteforce_loops_PM2R    : 0.12553, 0.12584, 0.12592
solution_python          : 0.13472, 0.13540, 0.13694
bruteforce_sum_PM2R      : 0.15820, 0.15849, 0.16021
perm_radixI_PM2R         : 0.17101, 0.17148, 0.17229
perm_radixR_PM2R         : 0.17891, 0.18087, 0.18366
perm_fenwick_PM2R        : 0.20554, 0.20708, 0.21412
fenwick_inline_PM2R      : 0.21161, 0.21163, 0.22047
merge_count_BM           : 0.24125, 0.24261, 0.24565
count_inversions_NiklasB : 0.25712, 0.25754, 0.25778
merge_PM2R               : 0.26477, 0.26566, 0.31297
fenwick_PM2R             : 0.28178, 0.28216, 0.29069
count_inversion_mkso     : 0.30286, 0.30290, 0.30652
inv_cnt_ZheHu            : 0.32024, 0.32041, 0.32447
reversePairs_nomanpouigt : 0.45812, 0.45822, 0.46172
Value: 98

Size = 40, hi = 20, 512 loops
solutionE_TimBabych      : 0.05784, 0.05787, 0.05958
solution_TimBabych       : 0.06452, 0.06475, 0.06479
perm_sum_PM2R            : 0.07254, 0.07261, 0.07263
rank_sum_PM2R            : 0.08537, 0.08540, 0.08572
ltree_count_PM2R         : 0.11744, 0.11749, 0.11792
solution_python          : 0.14262, 0.14285, 0.14465
perm_radixI_PM2R         : 0.18774, 0.18776, 0.18922
perm_radixR_PM2R         : 0.19425, 0.19435, 0.19609
bruteforce_loops_PM2R    : 0.21500, 0.21511, 0.21686
perm_fenwick_PM2R        : 0.23338, 0.23375, 0.23674
fenwick_inline_PM2R      : 0.24947, 0.24958, 0.25189
bruteforce_sum_PM2R      : 0.27627, 0.27646, 0.28041
merge_count_BM           : 0.28059, 0.28128, 0.28294
count_inversions_NiklasB : 0.28557, 0.28759, 0.29022
merge_PM2R               : 0.29886, 0.29928, 0.30317
fenwick_PM2R             : 0.30241, 0.30259, 0.35237
count_inversion_mkso     : 0.34252, 0.34356, 0.34441
inv_cnt_ZheHu            : 0.37468, 0.37569, 0.37847
reversePairs_nomanpouigt : 0.50725, 0.50770, 0.50943
Value: 369

Size = 80, hi = 40, 256 loops
solutionE_TimBabych      : 0.06339, 0.06373, 0.06513
solution_TimBabych       : 0.06984, 0.06994, 0.07009
perm_sum_PM2R            : 0.09171, 0.09172, 0.09186
rank_sum_PM2R            : 0.10468, 0.10474, 0.10500
ltree_count_PM2R         : 0.14416, 0.15187, 0.18541
solution_python          : 0.17415, 0.17423, 0.17451
perm_radixI_PM2R         : 0.20676, 0.20681, 0.20936
perm_radixR_PM2R         : 0.21671, 0.21695, 0.21736
perm_fenwick_PM2R        : 0.26197, 0.26252, 0.26264
fenwick_inline_PM2R      : 0.28111, 0.28249, 0.28382
count_inversions_NiklasB : 0.31746, 0.32448, 0.32451
merge_count_BM           : 0.31964, 0.33842, 0.35276
merge_PM2R               : 0.32890, 0.32941, 0.33322
fenwick_PM2R             : 0.34355, 0.34377, 0.34873
count_inversion_mkso     : 0.37689, 0.37698, 0.38079
inv_cnt_ZheHu            : 0.42923, 0.42941, 0.43249
bruteforce_loops_PM2R    : 0.43544, 0.43601, 0.43902
bruteforce_sum_PM2R      : 0.52106, 0.52160, 0.52531
reversePairs_nomanpouigt : 0.57805, 0.58156, 0.58252
Value: 1467

Size = 160, hi = 80, 128 loops
solutionE_TimBabych      : 0.06766, 0.06784, 0.06963
solution_TimBabych       : 0.07433, 0.07489, 0.07516
perm_sum_PM2R            : 0.13143, 0.13175, 0.13179
rank_sum_PM2R            : 0.14428, 0.14440, 0.14922
solution_python          : 0.20072, 0.20076, 0.20084
ltree_count_PM2R         : 0.20314, 0.20583, 0.24776
perm_radixI_PM2R         : 0.23061, 0.23078, 0.23525
perm_radixR_PM2R         : 0.23894, 0.23915, 0.24234
perm_fenwick_PM2R        : 0.30984, 0.31181, 0.31503
fenwick_inline_PM2R      : 0.31933, 0.32680, 0.32722
merge_count_BM           : 0.36003, 0.36387, 0.36409
count_inversions_NiklasB : 0.36796, 0.36814, 0.37106
merge_PM2R               : 0.36847, 0.36848, 0.37127
fenwick_PM2R             : 0.37833, 0.37847, 0.38095
count_inversion_mkso     : 0.42746, 0.42747, 0.43184
inv_cnt_ZheHu            : 0.48969, 0.48974, 0.49293
reversePairs_nomanpouigt : 0.67791, 0.68157, 0.72420
bruteforce_loops_PM2R    : 0.82816, 0.83175, 0.83282
bruteforce_sum_PM2R      : 1.03322, 1.03378, 1.03562
Value: 6194

Size = 320, hi = 160, 64 loops
solutionE_TimBabych      : 0.07467, 0.07470, 0.07483
solution_TimBabych       : 0.08036, 0.08066, 0.08077
perm_sum_PM2R            : 0.21142, 0.21201, 0.25766
solution_python          : 0.22410, 0.22644, 0.22897
rank_sum_PM2R            : 0.22820, 0.22851, 0.22877
ltree_count_PM2R         : 0.24424, 0.24595, 0.24645
perm_radixI_PM2R         : 0.25690, 0.25710, 0.26191
perm_radixR_PM2R         : 0.26501, 0.26504, 0.26729
perm_fenwick_PM2R        : 0.33483, 0.33507, 0.33845
fenwick_inline_PM2R      : 0.34413, 0.34484, 0.35153
merge_count_BM           : 0.39875, 0.39919, 0.40302
fenwick_PM2R             : 0.40434, 0.40439, 0.40845
merge_PM2R               : 0.40814, 0.41531, 0.51417
count_inversions_NiklasB : 0.41681, 0.42009, 0.42128
count_inversion_mkso     : 0.47132, 0.47192, 0.47385
inv_cnt_ZheHu            : 0.54468, 0.54750, 0.54893
reversePairs_nomanpouigt : 0.76164, 0.76389, 0.80357
bruteforce_loops_PM2R    : 1.59125, 1.60430, 1.64131
bruteforce_sum_PM2R      : 2.03734, 2.03834, 2.03975
Value: 24959

Run 2

Size = 640, hi = 320, 8 loops
solutionE_TimBabych      : 0.04135, 0.04374, 0.04575
ltree_count_PM2R         : 0.06738, 0.06758, 0.06874
perm_radixI_PM2R         : 0.06928, 0.06943, 0.07019
fenwick_inline_PM2R      : 0.07850, 0.07856, 0.08059
perm_fenwick_PM2R        : 0.08151, 0.08162, 0.08170
perm_sum_PM2R            : 0.09122, 0.09133, 0.09221
rank_sum_PM2R            : 0.09549, 0.09603, 0.11270
merge_count_BM           : 0.10733, 0.10807, 0.11032
count_inversions_NiklasB : 0.12460, 0.19865, 0.20205
solution_python          : 0.13514, 0.13585, 0.13814

Size = 1280, hi = 640, 8 loops
solutionE_TimBabych      : 0.04714, 0.04742, 0.04752
perm_radixI_PM2R         : 0.15325, 0.15388, 0.15525
solution_python          : 0.15709, 0.15715, 0.16076
fenwick_inline_PM2R      : 0.16048, 0.16160, 0.16403
ltree_count_PM2R         : 0.16213, 0.16238, 0.16428
perm_fenwick_PM2R        : 0.16408, 0.16416, 0.16449
count_inversions_NiklasB : 0.19755, 0.19833, 0.19897
merge_count_BM           : 0.23736, 0.23793, 0.23912
perm_sum_PM2R            : 0.32946, 0.32969, 0.33277
rank_sum_PM2R            : 0.34637, 0.34756, 0.34858

Size = 2560, hi = 1280, 8 loops
solutionE_TimBabych      : 0.10898, 0.11005, 0.11025
perm_radixI_PM2R         : 0.33345, 0.33352, 0.37656
ltree_count_PM2R         : 0.34670, 0.34786, 0.34833
perm_fenwick_PM2R        : 0.34816, 0.34879, 0.35214
fenwick_inline_PM2R      : 0.36196, 0.36455, 0.36741
solution_python          : 0.36498, 0.36637, 0.40887
count_inversions_NiklasB : 0.42274, 0.42745, 0.42995
merge_count_BM           : 0.50799, 0.50898, 0.50917
perm_sum_PM2R            : 1.27773, 1.27897, 1.27951
rank_sum_PM2R            : 1.29728, 1.30389, 1.30448

Size = 5120, hi = 2560, 8 loops
solutionE_TimBabych      : 0.26914, 0.26993, 0.27253
perm_radixI_PM2R         : 0.71416, 0.71634, 0.71753
perm_fenwick_PM2R        : 0.71976, 0.72078, 0.72078
fenwick_inline_PM2R      : 0.72776, 0.72804, 0.73143
ltree_count_PM2R         : 0.81972, 0.82043, 0.82290
solution_python          : 0.83714, 0.83756, 0.83962
count_inversions_NiklasB : 0.87282, 0.87395, 0.92087
merge_count_BM           : 1.09496, 1.09584, 1.10207
rank_sum_PM2R            : 5.02564, 5.06277, 5.06666
perm_sum_PM2R            : 5.09088, 5.12999, 5.13512

Size = 10240, hi = 5120, 8 loops
solutionE_TimBabych      : 0.71556, 0.71718, 0.72201
perm_radixI_PM2R         : 1.54785, 1.55096, 1.55515
perm_fenwick_PM2R        : 1.55103, 1.55353, 1.59298
fenwick_inline_PM2R      : 1.57118, 1.57240, 1.57271
ltree_count_PM2R         : 1.76240, 1.76247, 1.80944
count_inversions_NiklasB : 1.86543, 1.86851, 1.87208
solution_python          : 2.01490, 2.01519, 2.06423
merge_count_BM           : 2.35215, 2.35301, 2.40023
rank_sum_PM2R            : 20.07048, 20.08399, 20.13200
perm_sum_PM2R            : 20.10187, 20.12551, 20.12683

Run 3
Size = 20480, hi = 10240, 4 loops
solutionE_TimBabych      : 1.07636, 1.08243, 1.09569
perm_radixI_PM2R         : 1.59579, 1.60519, 1.61785
perm_fenwick_PM2R        : 1.66885, 1.68549, 1.71109
fenwick_inline_PM2R      : 1.72073, 1.72752, 1.77217
ltree_count_PM2R         : 1.96900, 1.97820, 2.02578
count_inversions_NiklasB : 2.03257, 2.05005, 2.18548
merge_count_BM           : 2.46768, 2.47377, 2.52133
solution_python          : 2.49833, 2.50179, 3.79819

Size = 40960, hi = 20480, 4 loops
solutionE_TimBabych      : 3.51733, 3.52008, 3.56996
perm_radixI_PM2R         : 3.51736, 3.52365, 3.56459
perm_fenwick_PM2R        : 3.76097, 3.80900, 3.87974
fenwick_inline_PM2R      : 3.95099, 3.96300, 3.99748
ltree_count_PM2R         : 4.49866, 4.54652, 5.39716
count_inversions_NiklasB : 4.61851, 4.64303, 4.73026
merge_count_BM           : 5.31945, 5.35378, 5.35951
solution_python          : 6.78756, 6.82911, 6.98217

Size = 81920, hi = 40960, 4 loops
perm_radixI_PM2R         : 7.68723, 7.71986, 7.72135
perm_fenwick_PM2R        : 8.52404, 8.53349, 8.53710
fenwick_inline_PM2R      : 8.97082, 8.97561, 8.98347
ltree_count_PM2R         : 10.01142, 10.01426, 10.03216
count_inversions_NiklasB : 10.60807, 10.62424, 10.70425
merge_count_BM           : 11.42149, 11.42342, 11.47003
solutionE_TimBabych      : 12.83390, 12.83485, 12.89747
solution_python          : 19.66092, 19.67067, 20.72204

Size = 163840, hi = 81920, 4 loops
perm_radixI_PM2R         : 17.14153, 17.16885, 17.22240
perm_fenwick_PM2R        : 19.25944, 19.27844, 20.27568
fenwick_inline_PM2R      : 19.78221, 19.80219, 19.80766
ltree_count_PM2R         : 22.42240, 22.43259, 22.48837
count_inversions_NiklasB : 22.97341, 23.01516, 23.98052
merge_count_BM           : 24.42683, 24.48559, 24.51488
solutionE_TimBabych      : 60.96006, 61.20145, 63.71835
solution_python          : 73.75132, 73.79854, 73.95874

Size = 327680, hi = 163840, 4 loops
perm_radixI_PM2R         : 36.56715, 36.60221, 37.05071
perm_fenwick_PM2R        : 42.21616, 42.21838, 42.26053
fenwick_inline_PM2R      : 43.04987, 43.09075, 43.13287
ltree_count_PM2R         : 49.87400, 50.08509, 50.69292
count_inversions_NiklasB : 50.74591, 50.75012, 50.75551
merge_count_BM           : 52.37284, 52.51491, 53.43003
solutionE_TimBabych      : 373.67198, 377.03341, 377.42360
solution_python          : 411.69178, 411.92691, 412.83856

Size = 655360, hi = 327680, 4 loops
perm_radixI_PM2R         : 78.51927, 78.66327, 79.46325
perm_fenwick_PM2R        : 90.64711, 90.80328, 91.76126
fenwick_inline_PM2R      : 93.32482, 93.39086, 94.28880
count_inversions_NiklasB : 107.74393, 107.80036, 108.71443
ltree_count_PM2R         : 109.11328, 109.23592, 110.18247
merge_count_BM           : 111.05633, 111.07840, 112.05861
solutionE_TimBabych      : 1830.46443, 1836.39960, 1849.53918
solution_python          : 1911.03692, 1912.04484, 1914.69786
1
répondu PM 2Ring 2017-12-21 13:02:18

j'ai récemment eu à le faire dans la R:

inversionNumber <- function(x){
    mergeSort <- function(x){
        if(length(x) == 1){
            inv <- 0
        } else {
            n <- length(x)
            n1 <- ceiling(n/2)
            n2 <- n-n1
            y1 <- mergeSort(x[1:n1])
            y2 <- mergeSort(x[n1+1:n2])
            inv <- y1$inversions + y2$inversions
            x1 <- y1$sortedVector
            x2 <- y2$sortedVector
            i1 <- 1
            i2 <- 1
            while(i1+i2 <= n1+n2+1){
                if(i2 > n2 || i1 <= n1 && x1[i1] <= x2[i2]){
                    x[i1+i2-1] <- x1[i1]
                    i1 <- i1 + 1
                } else {
                    inv <- inv + n1 + 1 - i1
                    x[i1+i2-1] <- x2[i2]
                    i2 <- i2 + 1
                }
            }
        }
        return (list(inversions=inv,sortedVector=x))
    }
    r <- mergeSort(x)
    return (r$inversions)
}
0
répondu Museful 2013-11-26 13:58:43

implémentation de Java:

import java.lang.reflect.Array;
import java.util.Arrays;


public class main {

public static void main(String[] args) {
    int[] arr = {6, 9, 1, 14, 8, 12, 3, 2};
    System.out.println(findinversion(arr,0,arr.length-1));
}

public static int findinversion(int[] arr,int beg,int end) {
    if(beg >= end)
        return 0;

    int[] result = new int[end-beg+1];
    int index = 0;
    int mid = (beg+end)/2;
    int count = 0, leftinv,rightinv;
    //System.out.println("...."+beg+"   "+end+"  "+mid);
    leftinv = findinversion(arr, beg, mid);
    rightinv = findinversion(arr, mid+1, end);
    l1:
    for(int i = beg, j = mid+1; i<=mid || j<=end;/*index < result.length;*/ ) {
        if(i>mid) {
            for(;j<=end;j++)
                result[index++]=arr[j];
            break l1;
        }
        if(j>end) {
            for(;i<=mid;i++)
                result[index++]=arr[i];
            break l1;
        }
        if(arr[i] <= arr[j]) {
            result[index++]=arr[i];
            i++;    
        } else {
            System.out.println(arr[i]+"  "+arr[j]);
            count = count+ mid-i+1;
            result[index++]=arr[j];
            j++;    
        }
    }

    for(int i = 0, j=beg; i< end-beg+1; i++,j++)
        arr[j]= result[i];
    return (count+leftinv+rightinv);
    //System.out.println(Arrays.toString(arr));
}

}
0
répondu Anwit 2014-01-12 15:31:42

voici ma prise en utilisant Scala:

trait MergeSort {
  def mergeSort(ls: List[Int]): List[Int] = {
    def merge(ls1: List[Int], ls2: List[Int]): List[Int] =
      (ls1, ls2) match {
        case (_, Nil) => ls1
        case (Nil, _) => ls2
        case (lowsHead :: lowsTail, highsHead :: highsTail) =>
          if (lowsHead <= highsHead) lowsHead :: merge(lowsTail, ls2)
          else highsHead :: merge(ls1, highsTail)
      }

    ls match {
      case Nil => Nil
      case head :: Nil => ls
      case _ =>
        val (lows, highs) = ls.splitAt(ls.size / 2)
        merge(mergeSort(lows), mergeSort(highs))
    }
  }
}

object InversionCounterApp extends App with MergeSort {
  @annotation.tailrec
  def calculate(list: List[Int], sortedListZippedWithIndex: List[(Int, Int)], counter: Int = 0): Int =
    list match {
      case Nil => counter
      case head :: tail => calculate(tail, sortedListZippedWithIndex.filterNot(_._1 == 1), counter + sortedListZippedWithIndex.find(_._1 == head).map(_._2).getOrElse(0))
    }

  val list: List[Int] = List(6, 9, 1, 14, 8, 12, 3, 2)
  val sortedListZippedWithIndex: List[(Int, Int)] = mergeSort(list).zipWithIndex
  println("inversion counter = " + calculate(list, sortedListZippedWithIndex))
  // prints: inversion counter = 28 
}
0
répondu Venkat Sudheer Reddy Aedama 2014-01-27 01:35:32

je pense que la réponse d'el diablo peut être optimisée pour supprimer l'étape 2b dans laquelle nous supprimons les éléments déjà traités.

à la place Nous pouvons définir

# d'inversion pour x = position de x dans le tableau trié - position de x dans le tableau d'origine

0
répondu Shireesh 2014-02-09 07:05:53

code C facile à comprendre:

#include<stdio.h>
#include<stdlib.h>

//To print an array
void print(int arr[],int n)
{
    int i;
    for(i=0,printf("\n");i<n;i++)
        printf("%d ",arr[i]);
    printf("\n");
}

//Merge Sort
int merge(int arr[],int left[],int right[],int l,int r)
{
    int i=0,j=0,count=0;
    while(i<l || j<r)
    {
        if(i==l)
        {
            arr[i+j]=right[j];
            j++;
        }
        else if(j==r)
        {
            arr[i+j]=left[i];
            i++;
        }
        else if(left[i]<=right[j])
        {
            arr[i+j]=left[i];
            i++;
        }
        else
        {
            arr[i+j]=right[j];
            count+=l-i;
            j++;
        }
    }
    //printf("\ncount:%d\n",count);
    return count;
}

//Inversion Finding
int inversions(int arr[],int high)
{
    if(high<1)
        return 0;

    int mid=(high+1)/2;
    int left[mid];
    int right[high-mid+1];

    int i,j;
    for(i=0;i<mid;i++)
        left[i]=arr[i];


    for(i=high-mid,j=high;j>=mid;i--,j--)
        right[i]=arr[j];

    //print(arr,high+1);
    //print(left,mid);
    //print(right,high-mid+1);

    return inversions(left,mid-1) + inversions(right,high-mid) + merge(arr,left,right,mid,high-mid+1);

}
int main()
{
    int arr[]={6,9,1,14,8,12,3,2};
    int n=sizeof(arr)/sizeof(arr[0]);
    print(arr,n);
    printf("%d ",inversions(arr,n-1));
    return 0;
}
0
répondu Jerky 2014-07-05 23:07:24

voici ma solution O (N log n) en Ruby:

def solution(t)
    sorted, inversion_count = sort_inversion_count(t)
    return inversion_count
end

def sort_inversion_count(t)
    midpoint = t.length / 2
    left_half = t[0...midpoint]
    right_half = t[midpoint..t.length]

    if midpoint == 0
        return t, 0
    end

    sorted_left_half, left_half_inversion_count = sort_inversion_count(left_half)
    sorted_right_half, right_half_inversion_count = sort_inversion_count(right_half)

    sorted = []
    inversion_count = 0
    while sorted_left_half.length > 0 or sorted_right_half.length > 0
        if sorted_left_half.empty?
            sorted.push sorted_right_half.shift
        elsif sorted_right_half.empty?
            sorted.push sorted_left_half.shift
        else
            if sorted_left_half[0] > sorted_right_half[0]
                inversion_count += sorted_left_half.length
                sorted.push sorted_right_half.shift
            else
                sorted.push sorted_left_half.shift
            end
        end
    end

    return sorted, inversion_count + left_half_inversion_count + right_half_inversion_count
end

et certains cas d'essai:

require "minitest/autorun"

class TestCodility < Minitest::Test
    def test_given_example
        a = [-1, 6, 3, 4, 7, 4]
        assert_equal solution(a), 4
    end

    def test_empty
        a = []
        assert_equal solution(a), 0
    end

    def test_singleton
        a = [0]
        assert_equal solution(a), 0
    end

    def test_none
        a = [1,2,3,4,5,6,7]
        assert_equal solution(a), 0
    end

    def test_all
        a = [5,4,3,2,1]
        assert_equal solution(a), 10
    end

    def test_clones
        a = [4,4,4,4,4,4]
        assert_equal solution(a), 0
    end
end
0
répondu Brandon 2014-08-05 03:13:46

la meilleure façon optimisée sera de le résoudre par le tri de fusion où va se fusionner nous pouvons vérifier combien d'inversions sont nécessaires en comparant la gauche et la droite tableau. Chaque fois que l'élément au tableau de gauche est plus grand que l'élément au tableau de droite, il sera l'inversion.

Fusion tri Approche :-

voici le code . Le Code est exactement le même que le tri de fusion sauf l'extrait de code sous la méthode mergeToParent où je compte l'inversion à la condition "else" de (left[leftunPicked] < right[rightunPicked])

public class TestInversionThruMergeSort {

    static int count =0;

    public static void main(String[] args) {
        int[] arr = {6, 9, 1, 14, 8, 12, 3, 2};


        partition(arr);

        for (int i = 0; i < arr.length; i++) {

            System.out.println(arr[i]);
        }

        System.out.println("inversions are "+count);

    }

    public static void partition(int[] arr) {

        if (arr.length > 1) {

            int mid = (arr.length) / 2;
            int[] left = null;

            if (mid > 0) {
                left = new int[mid];

                for (int i = 0; i < mid; i++) {
                    left[i] = arr[i];
                }
            }

            int[] right = new int[arr.length - left.length];

            if ((arr.length - left.length) > 0) {
                int j = 0;
                for (int i = mid; i < arr.length; i++) {
                    right[j] = arr[i];
                    ++j;
                }
            }

            partition(left);
            partition(right);
            mergeToParent(left, right, arr);
        }

    }

    public static void mergeToParent(int[] left, int[] right, int[] parent) {

        int leftunPicked = 0;
        int rightunPicked = 0;
        int parentIndex = -1;

        while (rightunPicked < right.length && leftunPicked < left.length) {

            if (left[leftunPicked] < right[rightunPicked]) {
                parent[++parentIndex] = left[leftunPicked];
                ++leftunPicked;

            } else {
                count = count + left.length-leftunPicked;
                if ((rightunPicked < right.length)) {
                    parent[++parentIndex] = right[rightunPicked];
                    ++rightunPicked;
                }
            }

        }

        while (leftunPicked < left.length) {
            parent[++parentIndex] = left[leftunPicked];
            ++leftunPicked;
        }

        while (rightunPicked < right.length) {
            parent[++parentIndex] = right[rightunPicked];
            ++rightunPicked;
        }

    }

}

une autre approche où nous pouvons comparer le tableau d'entrées avec le tableau trié: - Cette implémentation de réponse Diablo. Bien que cette approche ne devrait pas être préférée car enlever les éléments n d'un tableau ou d'une liste est log(n^2).

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;


public class TestInversion {

    public static void main(String[] args) {

        Integer [] arr1 = {6, 9, 1, 14, 8, 12, 3, 2};

        List<Integer> arr = new ArrayList(Arrays.asList(arr1));
        List<Integer> sortArr = new ArrayList<Integer>();

        for(int i=0;i<arr.size();i++){
            sortArr.add(arr.get(i));

        }


        Collections.sort(sortArr);

        int inversion = 0;

        Iterator<Integer> iter = arr.iterator();

        while(iter.hasNext()){

            Integer el = (Integer)iter.next();
            int index = sortArr.indexOf(el);

            if(index+1 > 1){
                inversion = inversion + ((index+1)-1);
            }

            //iter.remove();
            sortArr.remove(el);

        }

        System.out.println("Inversions are "+inversion);




    }


}
0
répondu M Sach 2016-08-02 12:57:02