Breve spiegazione.Trovare un periodo di sequenza eventualmente finale
Ho una sequenza di numeri [0, 1, 4, 0, 0, 1, 1, 2, 3, 7, 0, 0, 1, 1, 2, 3, 7, 0, 0, 1, 1, 2, 3, 7, 0, 0, 1, 1, 2, 3, 7]
. Come vedi, dal valore 3-rd la sequenza è periodica con un periodo [0, 0, 1, 1, 2, 3, 7]
.
Sto tentando di estrarre automaticamente questo periodo da questa sequenza. Il problema è che né conosco la durata del periodo, né so da quale posizione la sequenza diventa periodica.
completa spiegazione (potrebbe richiedere un po 'di matematica)
sto imparando la teoria dei giochi combinatoria e una pietra miliare di questa teoria richiede uno per calcolare Grundy values di un grafico del gioco. Questo produce una sequenza infinita, che in molti casi diventa eventually periodic.
Ho trovato un modo per calcolare in modo efficiente i valori di grundy (mi restituisce una sequenza). Vorrei estrarre automaticamente l'offset e il periodo di questa sequenza. Sono consapevole che vedendo una parte della sequenza [1, 2, 3, 1, 2, 3]
non si può essere certi che [1, 2, 3]
sia un punto (chi sa potrebbe essere il prossimo numero è 4
, che rompe l'ipotesi), ma non mi interessa la complessità (presumo che la sequenza è sufficiente per trovare il periodo reale). Anche il problema è che la sequenza può fermarsi nel mezzo del periodo: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, ...]
(il periodo è ancora 1, 2, 3
).
Devo anche trovare l'offset e il periodo più piccoli. Ad esempio per la sequenza originale, l'offset può essere [0, 1, 4, 0, 0]
e il periodo [1, 1, 2, 3, 7, 0, 0]
, ma il più piccolo è [0, 1, 4]
e [0, 0, 1, 1, 2, 3, 7]
.
Il mio approccio inefficace è provare ogni offset possibile e ogni periodo possibile. Costruisci la sequenza usando questi dati e verifica se è uguale all'originale. Non ho fatto nessuna analisi normale, ma sembra che sia almeno quadratico in termini di complessità temporale.
Ecco il mio codice python rapida (non sono testati in modo corretto):
def getPeriod(arr):
min_offset, min_period, n = len(arr), len(arr), len(arr)
best_offset, best_period = [], []
for offset in xrange(n):
start = arr[:offset]
for period_len in xrange(1, (n - offset)/2):
period = arr[offset: offset+period_len]
attempt = (start + period * (n/period_len + 1))[:n]
if attempt == arr:
if period_len < min_period:
best_offset, best_period = start[::], period[::]
min_offset, min_period = len(start), period_len
elif period_len == min_period and len(start) < min_offset:
best_offset, best_period = start[::], period[::]
min_offset, min_period = len(start), period_len
return best_offset, best_period
Il che mi riporta quello che voglio per la mia sequenza originale:
offset [0, 1, 4]
period [0, 0, 1, 1, 2, 3, 7]
C'è qualcosa di più efficiente?
Non puoi farlo a meno che non ci sia un limite superiore und alla lunghezza del periodo. Una sequenza che sembra essere periodica può divergere dal modello dopo aver detto un miliardo di elementi. – Henry
@ Henry, grazie, ma ne sono al corrente e l'ho spiegato nella mia domanda: "Sono consapevole che vedendo una parte della sequenza [1, 2, 3, 1, 2, 3] non puoi essere certo che [ 1, 2, 3] è un punto (chi sa potrebbe essere il prossimo numero è 4, che interrompe il presupposto), ma non sono interessato a tali complessità (presumo che la sequenza sia sufficiente per trovare il periodo reale) ' –
Conosci l'algoritmo con il nome di "Knuth-Morris-Pratt"? – Pavel