web-dev-qa-db-fra.com

Trouver le nombre d'opérations de suppression puis d'ajout nécessaires pour trier un tableau donné

Ceci est une question d'entrevue. Un swap signifie supprimer tout élément du tableau et l'ajouter à l'arrière du même tableau. Étant donné un tableau d'entiers, recherchez le nombre minimum de swaps nécessaire pour trier le tableau.

Existe-t-il une solution meilleure que O(n^2)?

Par exemple:

Tableau d'entrée: [3124].

Le nombre de swaps: 2 ([3124] -> [1243] -> [1234]).

23
Michael

Cela pourrait fonctionner dans O(nlogn) même si nous n'assumons pas de tableau de valeurs consécutives.
Si nous le faisons - cela peut être fait dans O(n). Une façon de le faire est avec O(n) espace et O(nlogn) temps.
Étant donné le tableau A triez-le (O(nlogn)) dans un deuxième tableau B.
maintenant ... (les tableaux sont indexés à partir de 1)

swaps = 0
b = 1
for a = 1 to len(A)
  if A[a] == B[b]
    b = b + 1
  else
    swaps = swaps + 1
8
Itay Karo

Le problème se résume à trouver le préfixe le plus long du tableau trié qui apparaît comme une sous-séquence dans le tableau d'entrée. Cela détermine les éléments qui pas doivent être triés. Les éléments restants devront être supprimés un par un, du plus petit au plus grand, et ajoutés à l'arrière.

Dans votre exemple, [3, 1, 2, 4], La sous-séquence déjà triée est [1, 2]. La solution optimale consiste à supprimer les deux éléments restants, 3 Et 4, Et à les ajouter à l'arrière. La solution optimale est donc deux "swaps".

La recherche de la sous-séquence peut être effectuée en O(n logn) temps en utilisant O(n) mémoire supplémentaire. Le pseudo-code suivant le fera (le code est également valide en Python):

l = [1, 2, 4, 3, 99, 98, 7]
s = sorted(l)
si = 0
for item in l:
  if item == s[si]:
    si += 1
print len(l) - si

Si, comme dans votre exemple, le tableau contient une permutation d'entiers de 1 À n, le problème peut être résolu en O(n) temps en utilisant O(1) Mémoire:

l = [1, 2, 3, 5, 4, 6]
s = 1
for item in l:
  if item == s:
    s += 1
print len(l) - s + 1

Plus généralement, la deuxième méthode peut être utilisée chaque fois que nous connaissons le tableau de sortie a priori et n'avons donc pas besoin de le trouver par tri.

23
NPE

Observation: Si un élément est échangé vers l'arrière, sa position précédente n'a pas d'importance. Aucun élément ne doit être échangé plus d'une fois.

Observation: Le dernier swap (le cas échéant) doit déplacer le plus grand élément.

Observation: Avant le swap, le tableau (hors dernier élément) doit être trié (par les anciens swaps, ou initialement)

algorithme de tri, en supposant que les valeurs sont consécutives: recherchez la sous-séquence triée la plus longue des éléments consécutifs (par valeur) commençant à 1:

3 1 5 2 4

permutez tour à tour tous les éléments supérieurs:

1 5 2 4 3

1 5 2 3 4

1 2 3 4 5

Pour trouver le nombre de swaps dans O (n), trouvez la longueur de la sous-séquence triée la plus longue d'éléments consécutifs commençant à 1:

  • attendu = 1
  • pour chaque élément dans l'ordre
    • si élément == attendu
      • attendu + = 1
  • retour attendu-1

alors le nombre de swaps = la longueur de l'entrée - sa sous-séquence triée la plus longue.

ne solution alternative (O (n ^ 2)) si l'entrée n'est pas une permutation de 1..n:

  • swaps = 0
  • boucle
    • trouver la première instance du plus grand élément et détecter si le tableau est trié
    • si le tableau est trié, retournez les swaps.
    • sinon, supprimez l'élément trouvé du tableau et incrémentez les échanges.

Encore une autre solution (O (n log n)), en supposant des éléments uniques:

  • envelopper chaque élément dans {oldPos, newPos, value}
  • faire une copie superficielle du tableau
  • trier le tableau par valeur
  • mémoriser la nouvelle position de chaque élément
  • exécuter l'algorithme de permutations sur les newPos 'dans la copie (non triée)

Si vous ne souhaitez pas copier le tableau d'entrée, triez plutôt par oldPos avant la dernière étape.

4
John Dvorak

c'est une solution O(n) qui fonctionne pour toutes les entrées:

static int minimumSwaps(int[] arr) {
        int swap=0;
        boolean visited[]=new boolean[arr.length];

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

            while(!visited[j]){
                visited[j]=true;
                j=arr[j]-1;
                cycle++;
            }

            if(cycle!=0)
                swap+=cycle-1;
        }
        return swap;
    }
}
2
MFCDev

Cela peut être fait dans O (n log n).

Trouvez d'abord l'élément minimum dans le tableau. Maintenant, recherchez l'élément max qui se produit avant cet élément. Appelez ceci max_left. Vous devez appeler swap() pour tous les éléments avant l'élément min du tableau.

Maintenant, recherchez la sous-séquence croissante la plus longue à droite de l'élément min, ainsi que la contrainte que vous devez ignorer les éléments dont les valeurs sont supérieures à max_left. Le nombre de swaps requis est size(array) - size(LIS).

Par exemple, considérez le tableau,

7 8 9 1 2 5 11 18

L'élément minimum dans le tableau est 1. Nous trouvons donc le max avant l'élément minimum.

7 8 9 | 1 2 5 11 18

max_left = 9

Maintenant, trouvez le LIS à droite de min avec des éléments <9 LIS = 1,2,5

Nombre d'échanges = 8 - 3 = 5

Dans les cas où l'élément max est nul, c'est-à-dire que min est le premier élément, recherchez le LIS du tableau et la réponse requise est size (array) -size (LIS)

Par exemple

2 5 4 3

max_left est nul. LIS est 2 3

Nombre d'échanges = taille (tableau) - taille (LIS) = 4-2 = 2

2
nkskalyan

Voici le code en python pour le nombre minimum de swaps,

def find_cycles(array):
   cycles = []
   remaining = set(array)
   while remaining:
      j = i = remaining.pop()
      cycle = [i]
      while True:
         j = array[j]
         if j == i:
             break
         array.append(j)
         remaining.remove(j)
      cycles.append(cycle)
   return cycles

def minimum_swaps(seq):
    return sum(len(cycle) - 1 for cycle in find_cycles(seq))
2
GraphicalDot
for(int count = 1; count<=length; count++)
{
    tempSwap=0; //it will count swaps per iteration
    for(int i=0; i<length-1; i++)
        if(a[i]>a[i+1])
        {
           swap(a[i],a[i+1]);
           tempSwap++;
        }
    if(tempSwap!=0) //check if array is already sorted!
        swap += tempSwap;
    else
        break;
}
System.out.println(swaps);
1
vipul

Écrire un programme JavaScript très simple pour trier un tableau et trouver le nombre de swaps:

  function findSwaps(){

    let arr = [4, 3, 1, 2];
    let swap = 0
    var n = arr.length
    for (let i = 0; i < n; i++) {
        for (let j = i + 1; j < n; j++) {
            if (arr[i] > arr[j]) {
                arr[i] = arr[i] + arr[j];
                arr[j] = arr[i] - arr[j];
                arr[i] = arr[i] - arr[j]
                swap = swap + 1
            }
        }
    }
    console.log(arr);
    console.log(swap)
  }
1
dinesh_malhotra
def minimumSwaps(arr):
    swaps = 0
    '''
    first sort the given array to determine the correct indexes 
    of its elements
    '''
    temp = sorted(arr)

    # compare unsorted array with the sorted one
    for i in range(len(arr)):
        '''
        if ith element in the given array is not at the correct index
        then swap it with the correct index, since we know the correct
        index because of sorting. 
        '''
        if arr[i] != temp[i]: 
          swaps += 1
          a = arr[i]
          arr[arr.index(temp[i])] = a
          arr[i] = temp[i]    
    return swaps
1
user7188158

Hear est ma solution en c # pour résoudre le nombre minimum de swaps requis pour court-circuiter un tableau A la fois, nous ne pouvons échanger que 2 éléments (à n'importe quelle position d'index).

public class MinimumSwaps2
{
    public static void minimumSwapsMain(int[] arr)
    {

        Dictionary<int, int> dic = new Dictionary<int, int>();
        Dictionary<int, int> reverseDIc = new Dictionary<int, int>();
        int temp = 0;
        int indx = 0;
  //find the maximum number from the array
        int maxno = FindMaxNo(arr);

        if (maxno == arr.Length)
        {
            for (int i = 1; i <= arr.Length; i++)
            {
                dic[i] = arr[indx];
                reverseDIc.Add(arr[indx], i);
                indx++;
            }
        }
        else
        {
            for (int i = 1; i <= arr.Length; i++)
            {
                if (arr.Contains(i))
                {
                    dic[i] = arr[indx];
                    reverseDIc.Add(arr[indx], i);
                    indx++;
                }

            }
        }

        int counter = FindMinSwaps(dic, reverseDIc, maxno);


    }
    static int FindMaxNo(int[] arr)
    {
        int maxNO = 0;
        for (int i = 0; i < arr.Length; i++)
        {
            if (maxNO < arr[i])
            {
                maxNO = arr[i];
            }
        }
        return maxNO;
    }
    static int FindMinSwaps(Dictionary<int, int> dic, Dictionary<int, int> reverseDIc, int maxno)
    {
        int counter = 0;
        int temp = 0;
        for (int i = 1; i <= maxno; i++)
        {
            if (dic.ContainsKey(i))
            {
                if (dic[i] != i)
                {
                    counter++;
                    var myKey1 = reverseDIc[i];
                    temp = dic[i];
                    dic[i] = dic[myKey1];
                    dic[myKey1] = temp;

                    reverseDIc[temp] = reverseDIc[i];
                    reverseDIc[i] = i;
                }
            }
        }
        return counter;
    }
}
1
Nemani Satya Ramesh
int numSwaps(int arr[], int length) {
bool sorted = false; 
int swaps = 0;
while(!sorted) {
    int inversions = 0;
    int t1pos,t2pos,t3pos,t4pos = 0;
    for (int i =  1;i < length; ++i)
    {
        if(arr[i] < arr[i-1]){
            if(inversions){
                tie(t3pos,t4pos) = make_Tuple(i-1, i);
            }
            else tie(t1pos, t2pos) = make_Tuple(i-1, i);
            inversions++;
        }
        if(inversions == 2)
            break;
    }
    if(!inversions){
        sorted = true;
    }
    else if(inversions == 1) {
        swaps++; 
        int temp = arr[t2pos];
        arr[t2pos] = arr[t1pos];
        arr[t1pos] = temp;
    }
    else{
        swaps++;
        if(arr[t4pos] < arr[t2pos]){
            int temp = arr[t1pos];
            arr[t1pos] = arr[t4pos];
            arr[t4pos] = temp;
        }
        else{
            int temp = arr[t2pos];
            arr[t2pos] = arr[t1pos];
            arr[t1pos] = temp;
        }
    }
}
return swaps;
}

Ce code renvoie le nombre minimal de swaps requis pour trier un tableau sur place.

Par exemple, A [] = [7,3,4,1] En échangeant 1 et 7, nous obtenons [1,3,4,7]. de même B [] = [1,2,6,4,8,7,9]. Nous échangeons d'abord 6 avec 4, donc, B [] -> [1,2,4,6,8,7,9]. Puis 7 avec 8. Donc -> [1,2,4,6,7,8,9]

L'algorithme s'exécute en O (nombre de paires où la valeur à l'index i <la valeur à l'index i-1) ~ O(N).

1
user3245033

@ all, la solution acceptée fournie par @Itay karo et @NPE est totalement fausse car elle ne prend pas en compte la future commande d'éléments échangés ...

Il échoue pour de nombreux cas de test comme:

1 2 5 4

sortie correcte: 4

mais leurs codes donnent la sortie ...

explication: 3 1 2 5 4 ---> 1 2 5 4 3 ---> 1 2 4 3 5 ---> 1 2 3 5 4 ---> 1 2 3 4 5

PS: je ne peux pas y commenter à cause de la mauvaise réputation

1
user3207754

espace O (1) et O(N) (~ 2 * N) en supposant que l'élément min est 1 et que le tableau contient tous les nombres de 1 à N-1 sans aucune valeur en double. où N est la longueur du tableau.

int minimumSwaps(int[] a) {
    int swaps = 0;
    int i = 0;
    while(i < a.length) {
        int position = a[i] - 1;
        if(position != i) {
            int temp = a[position];
            a[position] = a[i];
            a[i] = temp;
            swaps++;
        } else {
            i++;
        }
    }
    return swaps;
}
0
Sumukha H S
int temp = 0, swaps = 0;
        for (int i = 0; i < arr.length;) {
            if (arr[i] != i + 1){ 
            //  System.out.println("Swapping --"+arr[arr[i] - 1] +"  AND -- "+arr[i]);
                temp = arr[arr[i] - 1];
                arr[arr[i] - 1] = arr[i];
                arr[i] = temp;
                ++swaps;
            } else
                ++i;
                //  System.out.println("value at position -- "+ i +" is set to -- "+ arr[i]);
        }
        return swaps;

C'est la réponse la plus optimisée que j'ai trouvée. C'est tellement simple. Vous comprendrez probablement d'un coup d'œil la boucle. Merci à Darryl au rang de hacker.

0
user2867654