10
votes

Comment vérifier si des permutations ont une égale parité?

Je cherche un moyen de vérifier si 2 permutations (représentés par des listes) sont de la même parité . Notez que je ne suis pas intéressé si elles sont même ou parité impaire , juste l'égalité.

Je suis nouveau à Python et ma solution naïve est donnée ci-dessous en réponse. J'attends avec impatience Python Gurus me montrant des astuces fraîches pour obtenir la même chose en code Python moindre et plus élégant.


2 commentaires

Une permutation est-elle une liste de cycles disjoints? Une liste de paires de transposition? Une liste de (s, σ (s)) paires (où σ est la permutation à être représentée)?


Outis: Je suppose que cela peut être les deux.


8 Réponses :


4
votes

Ma solution naïve: xxx


3 commentaires

La seule amélioration que je peux voir est que la recherche Perm1.index (Perm0 [LOC]) ne doit réellement vérifier Perm1 après LOC - Je ne sais pas comment exprimer cela efficacement en Python.


Je suppose que nous voudrions peut-être copier Perm1 afin que l'opération ne mute pas l'argument Perm1?


Douglas: Vous avez raison de faire une copie de Perm1. Je n'étais même pas conscient que les listes sont transmises par référence aux fonctions (et donc modifiables dans)!



5
votes

une variante mineure de la réponse précédente - Copie Perm1 et sauvegardez les recherches de tableau.

def arePermsEqualParity(perm0, perm1):
    """Check if 2 permutations are of equal parity.

    Assume that both permutation lists are of equal length
    and have the same elements. No need to check for these
    conditions.
    """
    perm1 = perm1[:] ## copy this list so we don't mutate the original

    transCount = 0
    for loc in range(len(perm0) - 1):                         # Do (len - 1) transpositions
        p0 = perm0[loc]
        p1 = perm1[loc]
        if p0 != p1:
            sloc = perm1[loc:].index(p0)+loc          # Find position in perm1
            perm1[loc], perm1[sloc] = p0, p1          # Swap in perm1
            transCount += 1

    # Even number of transpositions means equal parity
    if (transCount % 2) == 0:
        return True
    else:
        return False


0 commentaires

0
votes

Mon intuition me dit que, en comptant simplement les différences entre les deux permutations vous donnera un de plus que le nombre de swaps nécessaires pour obtenir de l'une à l'autre. Cela vous donnera à son tour la parité.

Cela signifie que vous n'avez pas besoin de faire les swaps de votre code du tout. P>

Par exemple: P>

ABCD, CDBA.


4 commentaires

Badc - 4 Différences - Seulement 2 swaps nécessaires.


Contre-échantillon: ABCD, BADC. Il y a quatre différences, mais seulement deux swaps. (Swap AB, Swap CD.) Je pense que la parité dépend du nombre de cycles.


Oups, on dirait que j'étais un peu en retard avec ça!


Et c'est pourquoi l'intuition est nulle. Laissez la raison prévaloir!



6
votes

Voici mon modification de votre code

  • Liste d'utilisation () Pour copier Perm1 - Cela signifie que vous pouvez passer des tuples, etc. dans la fonction, ce qui le rend plus générique li>
  • Utilisez énumumé () dans la boucle pour la boucle à la place de len (..) et des recherches de tableau pour le code NATATER LI>
  • Faites un PAP1_MAP et tenez-le à jour pour arrêter une recherche chère O (n) sur Perm1 et une liste de liste coûteuse LI>
  • Renvoyez le booléen directement plutôt que si ... retourne vrai sinon retour faux li> ul>

    Voici IT P>

    def arePermsEqualParity(perm0, perm1):
        """Check if 2 permutations are of equal parity.
    
        Assume that both permutation lists are of equal length
        and have the same elements. No need to check for these
        conditions.
        """
        perm1 = list(perm1) ## copy this into a list so we don't mutate the original
        perm1_map = dict((v, i) for i,v in enumerate(perm1))
        transCount = 0
        for loc, p0 in enumerate(perm0):
            p1 = perm1[loc]
            if p0 != p1:
                sloc = perm1_map[p0]                       # Find position in perm1
                perm1[loc], perm1[sloc] = p0, p1           # Swap in perm1
                perm1_map[p0], perm1_map[p1] = sloc, loc   # Swap the map
                transCount += 1
        # Even number of transpositions means equal parity
        return (transCount % 2) == 0
    


0 commentaires

7
votes

Si nous combinons les deux permutations, le résultat aura même une parité lorsque chaque permutation a la même parité et la même parité si elles ont une parité différente. Donc, si nous résolvons le problème de la parité fort>, il est trivial de comparer deux permutations différentes.

Parité forte> peut être déterminé comme suit: Choisissez un élément arbitraire, trouvez la position que la permutation Déplace cela pour répéter jusqu'à ce que vous reveniez à celui que vous avez commencé. Vous avez maintenant trouvé un cycle: la permutation fait pivoter tous ces éléments autour d'une position. Vous avez besoin d'un échange de moins que le nombre d'éléments du cycle pour l'annuler. Maintenant, choisissez un autre élément que vous n'avez pas encore traité et répété jusqu'à ce que vous ayez vu tous les éléments. Observez qu'au total, vous avez besoin d'un échange par élément moins un échange par cycle. P>

La complexité de temps est O (n) de la taille de la permutation. Notez que bien que nous ayons une boucle au sein d'une boucle, la boucle interne ne peut jamais parcourir une seule fois pour tout élément de la permutation. P>

def parity(p):
    return sum(
        1 for (x,px) in enumerate(p)
          for (y,py) in enumerate(p)
          if x<y and px>py
        )%2==0


3 commentaires

[P0 [P1 [I]] Pour i In Xrange (LEN (P0))] -> [P0 [I] pour I in P1] ?


Hehe, c'est tellement évident maintenant que vous le soulignez! Je vais éditer ceux-ci.


Merci beaucoup d'avoir souligné cette approche alternative! Il devient d'autant plus optimal (et utile) pour un scénario où Perm0 reste constant et comparé à de nombreuses listes Perm1.



2
votes

voici légèrement refactored Réponse de Weeble :

def arePermsEqualParity(perm0, perm1):
    """Whether permutations are of equal parity."""
    return parity(combine(perm0, perm1))

def combine(perm0, perm1):
    """Combine two permutations into one."""
    return map(perm0.__getitem__, perm1)

def parity(permutation):
    """Return even parity for the `permutation`."""
    return (len(permutation) - ncycles(permutation)) % 2 == 0

def ncycles(permutation):
    """Return number of cycles in the `permutation`."""
    ncycles = 0
    seen = [False] * len(permutation)
    for i, already_seen in enumerate(seen):
        if not already_seen:
            ncycles += 1
            # mark indices that belongs to the cycle
            j = i 
            while not seen[j]: 
                seen[j] = True
                j = permutation[j]
    return ncycles


0 commentaires

2
votes

La solution avec le dictionnaire est bogu. Ceci est la version de débogage: xxx

Les seules différences sont que l'échange dans le dictionnaire n'a pas été effectué correctement.


0 commentaires

0
votes
def equalparity(p,q):
    return sum([p[q[i]] > p[q[j]] for i in range(len(p)) for j in range(i)]) % 2 == 0

0 commentaires