Rang einer Permutation


WhitneyChia

Es gab also eine Frage, die ich hauptsächlich aufgrund von Rechenleistung oder mangelnder Rechenleistung nicht lösen konnte. Ich habe mich gefragt, wie ich das codieren soll, damit ich es tatsächlich auf meinem Computer ausführen kann. Der Kern der Fragen ist:

Angenommen, Sie haben eine Zeichenfolge 'xyz'und möchten alle eindeutigen Permutationen dieser Zeichenfolge finden. Dann sortieren Sie sie und finden den Index 'xyz'aus den eindeutigen Permutationen. Das schien einfach zu sein, aber sobald Sie eine wirklich lange Zeichenfolge erhalten, gibt mein Computer auf. Was ist der mathematische Weg, um dies zu umgehen, was mich zu Code führen würde, der tatsächlich auf meinem Laptop ausgeführt werden kann?

from itertools import permutations

def find_rank(n):
    perms = [''.join(p) for p in permutations(n)]
    perms = sorted(set(perms))
    loc = perms.index(n)
    return loc

Wenn ich diesen Code jedoch für eine Zeichenfolge ausführen möchte, die 100 Buchstaben lang ist, sind es einfach zu viele, als dass mein Computer damit umgehen könnte.

Bakuriu

Dieses Problem kann leicht gelöst werden, indem man es zuerst vereinfacht und rekursiv denkt.

Nehmen wir also zunächst an, dass alle Elemente in der Eingabesequenz eindeutig sind, dann ist die Menge der "eindeutigen" Permutationen einfach die Menge der Permutationen.

Um nun den Rang der Sequenz a_1, a_2, a_3, ..., a_nin ihren Permutationssätzen zu finden, können wir:

  1. Sortieren Sie die Reihenfolge, um zu erhalten b_1, b_2, ..., b_n. Diese Permutation hat per Definition Rang 0.

  2. Jetzt vergleichen wir a_1und b_1. Wenn sie gleich sind, können wir sie einfach aus dem Problem entfernen: Der Rang von a_1, a_2, ..., a_nwird der gleiche sein wie der Rang von gerecht a_2, ..., a_n.

  3. Andernfalls b_1 < a_1werden dann alle Permutationen, die mit beginnen b_1, kleiner als sein a_1, a_2, ..., a_n. Die Anzahl solcher Permutationen ist einfach zu berechnen, es ist einfach (n-1)! = (n-1)*(n-2)*(n-3)*...*1.

    Aber dann können wir unsere Sequenz weiter betrachten b_1, ..., b_n. Wenn ja b_2 < a_1, sind wieder alle Permutationen, die mit beginnen b_2, kleiner. Also sollten wir (n-1)!unseren Rang noch einmal erhöhen.

    Wir tun dies, bis wir einen Index finden, jwo b_j == a_j, und dann landen wir bei Punkt 2.

Dies kann ganz einfach implementiert werden:

import math

def permutation_rank(seq):
    ref = sorted(seq)
    if ref == seq:
        return 0
    else:
        rank = 0
        f = math.factorial(len(seq)-1)
        for x in ref:
            if x < seq[0]:
                rank += f
            else:
                rank += permutation_rank(seq[1:]) if seq[1:] else 0
                return rank

Die Lösung ist ziemlich schnell:

In [24]: import string
    ...: import random
    ...: seq = list(string.ascii_lowercase)
    ...: random.shuffle(seq)
    ...: print(*seq)
    ...: print(permutation_rank(seq))
    ...: 
r q n c d w s k a z b e m g u f i o l t j x p h y v
273956214557578232851005079

Zum Thema gleiche Elemente: Der Punkt, an dem sie ins Spiel kommen, (n-1)!ist die Anzahl der Permutationen, wobei jedes Element als von den anderen verschieden betrachtet wird. Wenn Sie eine Längenfolge naus Symbol s_1, ..., s_kund Symbol haben, s_jdie c_jmal angezeigt wird, beträgt die Anzahl der eindeutigen Permutationen `(n-1)! / (c_1! * c_2! * ... * c_k!).

Dies bedeutet, dass (n-1)!wir es nicht nur addieren , sondern durch diese Zahl dividieren müssen, und dass wir auch die Anzahl c_tder aktuellen Symbole, die wir in Betracht ziehen , um eins verringern möchten .

Dies kann folgendermaßen geschehen:

import math
from collections import Counter
from functools import reduce
from operator import mul

def permutation_rank(seq):
    ref = sorted(seq)
    counts = Counter(ref)

    if ref == seq:
        return 0
    else:
        rank = 0
        f = math.factorial(len(seq)-1)
        for x in sorted(set(ref)):
            if x < seq[0]:
                counts_copy = counts.copy()
                counts_copy[x] -= 1
                rank += f//(reduce(mul, (math.factorial(c) for c in counts_copy.values()), 1))
            else:
                rank += permutation_rank(seq[1:]) if seq[1:] else 0
                return rank

Ich bin mir ziemlich sicher, dass es eine Möglichkeit gibt, das Kopieren des Zählwörterbuchs zu vermeiden, aber im Moment bin ich müde, also lasse ich das als Übung für den Leser.

Als Referenz das Endergebnis:

In [44]: for i,x in enumerate(sorted(set(it.permutations('aabc')))):
    ...:     print(i, x, permutation_rank(x))
    ...:     
0 ('a', 'a', 'b', 'c') 0
1 ('a', 'a', 'c', 'b') 1
2 ('a', 'b', 'a', 'c') 2
3 ('a', 'b', 'c', 'a') 3
4 ('a', 'c', 'a', 'b') 4
5 ('a', 'c', 'b', 'a') 5
6 ('b', 'a', 'a', 'c') 6
7 ('b', 'a', 'c', 'a') 7
8 ('b', 'c', 'a', 'a') 8
9 ('c', 'a', 'a', 'b') 9
10 ('c', 'a', 'b', 'a') 10
11 ('c', 'b', 'a', 'a') 11

Und um zu zeigen, dass es effizient ist:

In [45]: permutation_rank('zuibibzboofpaoibpaybfyab')
Out[45]: 246218968687554178

Verwandte Artikel


Wenden Sie Rang in der Permutation einer Liste an

Shane Ich habe zwei Listen: l1 = [0, 1, 12, 33, 41, 52, 69, 7.2, 8.9, 9.91] l2 = [45, 51] Ich muss alle möglichen Kombinationen (ohne Wiederholung) l1mit einer Größe erhalten, die der Länge von entspricht l2. Wenden Sie dann eine Rangmetrik auf l2und l1(für j

Rang einer Matrix in ojAlgo

nhavt Ich verwende derzeit die ojAlgo v45.1.0. Ich habe eine Frage, wie man die Spur und die Summe einer Matrix erhält. Da ich eine Matrix in der Klasse PrimitiveDenseStore speichere, ist es nicht möglich, Methoden zum Berechnen des Trace und der Summe der Mat

Rang in einer Aufzählung vergleichen

Monica: Ich habe die folgende Aufzählung, die einen CardRank darstellt public enum CardRank { DEUCE('2'), TREY('3'), FOUR('4'), FIVE('5'), SIX('6'), SEVEN('7'), EIGHT('8'), NINE('9'), TEN('T'), JACK('J'), QUEEN('Q'), KING('K'), ACE('A'); priv

Matlab: Erstellen einer blockweisen Permutation

Avi Ich habe einen Vektor von 1 bis 40 und möchte ihn so mischen, dass jeder Block mit vier ganzen Zahlen (insgesamt zehn Blöcke) nur mit sich selbst gemischt wird. Beispiel: 3 4 2 1 | 7 6 5 8 | 9 11 10 12 | ... Meine ursprüngliche Idee war, zehn Permutationsv

Finden Sie den Rang einer Submatrix in Tensorflow

Lerner Ich habe eine Formmatrix g, [4, 4, 2, 2]in der ich den Rang von g[0, 0]finden g[1, 1]muss g[2, 2]und g[3, 3]die alle 2x2Matrizen sind. Ich habe den tf.rankOperator verwendet, aber er wird gals einzelnes Array behandelt, berechnet den Rang und gibt einen

Rang einer Variablen in einem Zähler

Kyrenia Ich habe Daten in einem Zähler gespeichert, z industries = Counter({'Automotive': 17, 'Commercial Banks': 10, 'Insurance': 4, 'Hospitals': 2, 'Other': 2}) Ich bin daran interessiert, den 'Index' (dh den 'Rang') einer bestimmten Variablen nachzuschlage

Pandas - Rang in verschiedenen Reihenfolgen mit einer Gruppe

Krieger Ich habe einen Datensatz, den ich nach der Gruppenvariablen ordnen möchte. Für Gruppe A möchte ich in aufsteigender Reihenfolge rangieren. Für Gruppe B möchte ich in absteigender Reihenfolge rangieren. Ich weiß nur, wie ich die Gruppe nach einer Reihen