si può fare in 0(n)
tempo e 0(1)
spazio utilizzando una versione modificata di un algoritmo di suffissi massima:
Da Jewels of Stringology: ciclico parità di parole
A rotazione una parola u di lunghezza n è una qualsiasi parola della forma u [k + 1 ... n] [l ... k]. Sia w, due parole della stessa lunghezza n. Si dice che siano equivalenti al ciclo se u (i) == w (j) per alcuni i, j.
Se le parole uew sono scritte come cerchi, sono equivalenti ciclici se i cerchi coincidono dopo le rotazioni appropriate.
Esistono diversi algoritmi di tempo lineare per testare l'equivalenza ciclica di due parole. La più semplice consiste nell'applicare qualsiasi algoritmo di corrispondenza delle stringhe per il modello pat = u e text = ww perché le parole u e w sono cicliche = equivalenti se pat si verifica nel testo.
Un altro algoritmo consiste nel trovare i suffissi massimi di uu e ww e controllare se sono identici sui prefissi della dimensione n. Abbiamo scelto questo problema perché esiste un algoritmo più semplice e interessante, che lavora simultaneamente in tempo lineare e spazio costante, il che merita la presentazione.
Algorithm Cyclic-Equivalence(u, w)
{ checks cyclic equality of u and w of common length n }
x := uu; y := ww;
i := 0; j := 0;
while (i < n) and (j < n) do begin
k := 1;
while x[i + k] = y[j + k] do k := k + 1;
if k > n then return true;
if x[i + k]> y[i + k] then i := i + k else j := j + k;
{ invariant }
end;
return false;
che tradotto in pitone diventa:
def cyclic_equiv(u, v):
n, i, j = len(u), 0, 0
if n != len(v):
return False
while i < n and j < n:
k = 1
while k <= n and u[(i + k) % n] == v[(j + k) % n]:
k += 1
if k > n:
return True
if u[(i + k) % n] > v[(j + k) % n]:
i += k
else:
j += k
return False
Esecuzione di alcuni esempi:
In [4]: a = [3,1,2,3,4]
In [5]: b =[3,4,3,1,2]
In [6]: cyclic_equiv(a,b)
Out[6]: True
In [7]: b =[3,4,3,2,1]
In [8]: cyclic_equiv(a,b)
Out[8]: False
In [9]: b =[3,4,3,2]
In [10]: cyclic_equiv(a,b)
Out[10]: False
In [11]: cyclic_equiv([1,2,3],[1,2,3])
Out[11]: True
In [12]: cyclic_equiv([3,1,2],[1,2,3])
Out[12]: True
Un approccio più semplice sarebbe quello di utilizzare un collections.deque per ruotare gli elementi :
def rot(l1,l2):
from collections import deque
if l1 == l2:
return True
# if length is different we cannot get a match
if len(l2) != len(l1):
return False
# if any elements are different we cannot get a match
if set(l1).difference(l2):
return False
l2,l1 = deque(l2),deque(l1)
for i in range(len(l1)):
l2.rotate() # l2.appendleft(d.pop())
if l1 == l2:
return True
return False
La quantità di duplicati è importante? Esempio: [1,2,3] e [3,1,2,3] sono diversi? –
Sì, quelli sono decisamente diversi. –
Bene, in tal caso, mantieni un conteggio delle lunghezze e rifiuta una partita se sono diverse. –