Testare se esiste un intero K per aggiungere una sequenza per renderlo una successiva di un'altra sequenza

cs.stackexchange https://cs.stackexchange.com/questions/117706

Domanda

Supponiamo che la sequenza $ A $ contiene $ n $ interi $ A_1, A_2, A_3, \ LDOTS, A_N $ e Sequence $ B $ contiene $ m $ Integers $ B_1, B_2, B_3, \ LDOTS, B_M $ . Sappiamo che $ m \ geq n $ . Assumiamo senza perdita di generalità che entrambe le sequenze $ a $ e $ B $ sono ordinati in ordine crescente.

Qual è l'algoritmo più veloce per determinare se esiste un numero intero $ k $ in modo tale che la sequenza $ A_1 + K, A_2 + K, A_3 + K, \ LDOTS, A_N + K $ è una successiva della sequenza $ B $ ?

Ecco un algoritmo ingenuo, che prenderebbe $ o (n (m-n)) $ tempo. Conservare la sequenza $ B $ come hashtable. Per ogni elemento $ B_J $ della $ B $ (eccetto la più grande $ N $ elementi), utilizzare $ B_J-A_1 $ come la tua ipotesi a $ k $ ; È possibile verificare questa ipotesi controllando se ciascuna delle $ A_1 + K, \ Dots, A_N + K $ sono nell'Hashtable $ B $ . Questo richiede $ o (n) $ tempo previsto per ipotesi a $ k $ , e fai $ MN $ Indovina, quindi in totale il tempo di esecuzione previsto è $ o (n (n (mn)) $ . Possiamo fare di meglio?

Ho trovato questo problema durante il tentativo di abbinare due immagini binarie (testando se un'immagine contiene l'altra).

È stato utile?

Soluzione

Ecco un euristico che non funzionerà sempre, ma dovrebbe funzionare con alta probabilità se gli interi negli array sono scelti a caso da uno spazio abbastanza grande.

Inizializza un hashtable dei conteggi $ c $ a tutti gli zeri. Quindi, ripetere $ T $ volte: selezionare casualmente $ i, j $ , calcola $ B_J-A_I $ e incremento $ c [B_J-A_I] $ . Infine, ordina $ c $ da conteggi, dal numero più grande a più piccolo; Quindi per ciascuno dei valori più grandi di $ c [k '] $ , prova $ k' $ come la tua ipotesi a $ k $ e verificare ogni ipotesi.

Si noti che in ogni iterazione, la probabilità di incrementare $ c [k] $ è almeno $ 1 / m $ ; Considerando se $ l \ N K $ , ci aspettiamo $ c [l] $ per essere incrementato molto di più Raramente (supponendo che i numeri interi negli array siano casuali e abbastanza grandi). Quindi, dopo $ T $ iterazioni, ci aspettiamo $ \ mathbb {e} [c [k]] \ ge t / m $ ma $ \ mathbb {e} [c [l]] \ lt / m $ . Quindi, una volta $ T $ è abbastanza grande, $ c [k] $ dovrebbe essere più grande di ogni altro Entrata in $ c $ .

Quanto è grande $ T $ bisogno di essere? Mi aspetto che $ t= o (m \ log m) $ dovrebbe essere sufficiente, in base a un limite di teorema limite centrale per i conteggi $ C [l] $ , supponendo che siamo disposti ad accettare una piccola probabilità di errore (che può essere guidata in modo esponenziale). Il fattore costante nascosto dalla notazione Big-o potrebbe essere non banale.

Questo è solo un euristico, e ci saranno certamente input dove fallisce.

Altri suggerimenti

Ecco un algoritmo in esecuzione in $ \ mathcal {o} (n \ sqrt {n} + m \ log m) $ tempo.

Let $ W $ Dennare la funzione che per Integer $ T $ , conta il numero di coppie che la loro differenza è $ T $ : $ w (t)=lver \ {(x, y): x { In A, y \ in b, yx= t \} \ rvert $ . Se avessimo accesso a $ w w (t) $ potremmo semplicemente trovare il massimo e vedere se è $ N $ o no. L'idea principale è stimare $ W $ usando la trasformata di Fourier veloce. Se i numeri sono limitati, produrrà la soluzione esatta, altrimenti, si può utilizzare il modulo su un numero sufficientemente grande e quindi verificare le soluzioni una volta trovate.

Let $ n, m $ essere numeri interi (da definire in seguito) e $ u, v \ in \ MathBB {R} ^ N $ I vettori sono definiti come $$ u [i]=LTering \ {X \ in a \ Colon M-x \ Equiv I \ PMOD N \} \ RIVERS $$ $$ v [i]=LTering \ {y \ in b \ Colon m + y \ equiv i \ pmod n \} \ rvert $$ Let $ w= u * v $ Denota la convocazione circolare di questi due vettori. Quindi se c'è $ k $ tale $$ \ Forall X \ in a \ esiste y \ in b: y-x= k, $$ Quindi possiamo concludere $$ w [k \ bmod n]=sum_ {i: v [i] \ neq 0} v [i] u [ik \ bmod n]= n $$ . quale costruzione è il valore massimo che $ W $ può raggiungere. Pertanto, abbiamo solo bisogno di controllare se $ \ max_i w (i)= n $ o no. Quindi, verifichiamo la correttezza della soluzione controllando gli elementi originali. Computing $ W $ può essere eseguito da FFT e FFT inversa in $ \ MATHCAL {O} (N \ Log N) $ Tempo, e quindi trovare l'elemento massimo e verificarlo è necessario $ N $ passi, quindi complessiva $ \ Mathcal {O} (n \ log n) $ tempo e spazio.

Se i numeri in entrambi i set sono delimitati da $ N $ Questa è una soluzione esatta. Ma se scegli $ N $ troppo piccolo, $ w (i)= n $ può accadere a causa di collisioni. Quindi possiamo verificare tutti gli elementi per tutti gli indici che $ w (i) \ ge n $ ; Potrebbero esserci molti, ma il loro numero può essere limitato. Per avere $ \ ell $ tali indici, uno deve avere almeno $ 1 + 2 + \ Dots + \ Ell $ collisioni, che implica $$ P [\ LTERS \ {I \ Colon W [I] \ GE N \} \ Rvert \ Ge \ Ell] \ le P [\ testo {# collisioni} \ GE ( \ ell + 1) \ ell / 2]. $$ Ci sono $ NM $ Abbinamenti di elementi di $ a $ e $ B $ . Se scegliamo un numero primo $ N $ in modo tale che $ n> 2m $ e selezionare $ m $ uniformemente a caso da $ \ {1, \ dots, n \} $ , la probabilità di collisione è limitata da $ 1 / 2m $ , quindi dalla disuguaglianza di Markov è $$ \ Le \ frac {nm / n} {\ \ ell ^ 2/2} {\ \ \ frac {n} {\ ell ^ 2} $$ Quindi con probabilità il più vicino a $ 1 $ come desideri, $ \ ell=mathcal {o} (\ sqrt {n }) $ . Pertanto, la complessità complessiva del tempo dell'algoritmo è $$ \ Mathcal {o} (n \ sqrt {n} + m \ log m) $$ in quale $ m \ log m $ è il passaggio FFT e IFFT (dal momento che impostiamo $ n= 2m $ ) e $ n \ sqrt {n} $ è il passaggio di verifica.

Ci sono due modi in cui vedo per migliorare questo:

    .
  1. Si può eseguire $ \ log n $ separate istanze dell'algoritmo senza la verifica e prendere l'intersezione degli indici massimi che $ w [i] \ ge n $ (dopo lo spostamento di $ m $ ). Se si può dimostrare che il numero di collisioni condivise scende da $ 1/2 $ o qualche altra costante ogni volta, questo mostrerebbe un tempo di esecuzione totale di $ \ Mathcal {o} (m \ log ^ 2 m) $ .
  2. si può costruire un migliore meccanismo di hashing per $ U $ e $ V $ e utilizzare Momenti più alti per Markov e rendono la concentrazione più nitida.
  3. Tuttavia, se stai cercando una soluzione pratica che questo algoritmo potrebbe funzionare bene. Ad esempio, i TI

Comportamento T-Case $ \ ell \ circa \ sqrt {n} $ Si verifica solo quando i set sono quasi le progressioni aritmetiche.Se scegli gli elementi quasi in modo casuale, la garanzia sarà molto più forte.Inoltre, puoi fermare il passo di verifica non appena trovi un errore.

Questo è un algoritmo completamente diverso, che credo che funzioni in $ o (m \ log m) $ cassa peggiore e dovrebbe funzionare per numeri interi o reali.

Assumiamo che $ A $ e $ B $ sono già in ordine crescente, altrimenti spendere $ o (n \ log n + m \ log m) $ per ordinarli. Rafforziamo leggermente il requisito per l'algoritmo $ \ Mathcal {A} (A, B) $ per restituire tutti gli indici $ i $ i $ tali quella $ A $ può essere mappato a $ B $ con offset $ K= B_i-A_1 $ , il che significa che la mappatura inizia a $ B_i $ in poi. L'idea di alto livello è quella di risolvere i problemi secondari corrispondenti a un sottobosco di $ A $ e unire gli indici in un modo che rimangono solo soluzioni valide.

La ricorsione, tuttavia, dipende dal modo da chiudere $ A $ è a una progressione aritmetica. Formalmente, lascia che la periodicità $ \ tau (a) $ essere definito come: $$ \ Tau (A)=min \ {s \ in \ mathbb {n} ^ +: a_ {i + s + 1} -a_ {i + s}= A_ {i + 1} - A_I \ Text {per tutti Valid} I, S \} $$ A parole, questo significa elementi di $ A $ , sono periodici con un ciclo minimo $ \ tau (A) $ , fino ad alcuni offset.

Caso I ( $ \ tau (A) Let $ s=tau (a) $ e $ \ ell= A_S - A_1 $ . Calcola ricorsivamente $ i=mathcal {a} (A [1: s], b) $ . Un'osservazione è che se $ i, j \ in I $ , corrispondente a set di indici $ j_i, j_j $ , e $ B_J - B_I=ELL $ , l'indice set $ j_i, j_j $ può essere Concatenato per mostrare $ I \ in \ Mathcal {A} (A [1: 2S], B) $ . Questa è una semplice conseguenza di $ A $ essere $ s $ periodico e $ B_J= B_I + \ \ ELL $ Assicura che il set di indici $ j_j $ inizia dove $ J_i $ finisce. Permettere $$ r [i]=lver \ {j \ in I \ colon j> i, b_j - b_i \ text {divisible by} \ ell \} \ rvert $$ . Quindi, $ R [i] $ può essere calcolato in base a $ r [i '] $ < Class Class="Math-Container"> $ I '> I $ e il nuovo set indice $ I' $ , è gli indici che $ r [i] \ ge n / s $ . Il costo per questo passaggio è limitato da $ o (m) $ .

Caso II ( $ \ Tau (A)> N / 3 $ ) : per definizione, per $ s= n / 3 $ Dovrebbe esserci un indice $ i $ quella $ A_ {I + 1} -a_i \ neq a_ {i + 1 + s} -a_ {i + s} $ . Se $ i \ le n / 3 $ , avremo $ i, i + s \ le 2n / 3 $ < / span> che certifica che $ \ tau (A [1: 2n / 3])> n / 3 $ . Altrimenti, $ i> n / 3 $ implica che $ \ tau (A [n / 3: n])> n / 3 $ .

wlog assumere $ \ taau (a [1: 2n / 3)> n / 3 $ e scegliere la metà inferiore $ A '= A [1: N / 2] $ per ricompensare (altrimenti scegliere la metà superiore, seguirebbe gli stessi argomenti). Calcola ricorsivamente $ i=mathcal {a} (a ', b) $ . Per ogni indice $ i \ in I $ , controlla se il resto della sequenza può essere trovato in $ B $ . Poiché entrambe le sequenze sono ordinate che possono essere eseguite in $ o (n) $ passo per ogni indice, il che implica una classe complessiva $ O (| i | \ clot n) $ tempo per calcolare gli indici validi e restituirli come $ \ Mathcal {A} (A, B) $ . L'efficienza di questo passo si basa sulla seguente rivendicazione:

reclamo: $ | i | \ le 6m / n $ , il che significa che le soluzioni non sono troppa sovrapposizione.

Prova del reclamo: mostriamo $ | i |> 6m / n $ conduce a una contraddizione. Ogni indice $ i \ in I $ è il punto di partenza di un set di indici $ j_i={i= j_1, \ Dots, J_ {N / 2}}} \ SOTETETQ B $ , That Map $ A '$ a $ B $ fino ad alcuni offset. Col

Contenibile, ci sono almeno $ 3m $ indici: $$ \ sum_ {i \ in i} | J_i |= | I | n / 2 \ ge 6m / n \ cdot n / 2= 3m $$ Dal momento che $ | B |= m $ , dal principio di Pigeonhole, c'è almeno un indice $ x \ in B $ < / span> appare in 3 soluzioni separate: $$ \ esiste x \ in b, r, s, p \ in i \ duel \; x \ in j_r \ cap j_s \ cap j_p $$

Let $ s $ Sii la mediana dei tre $ r . Dal momento che $ x \ in j_s $ e $ | j_s |= n / 2 $ , $ x $ partizioni $ j_s $ a due parti, una delle quali dovrebbe avere meno di $ N / 4 $ indici, che assumiamo è la parte inferiore: $$ j_s={j_1= s, j_2, \ dots, j_ \ ell= x \}, \ ell \ le n / 4 $$ Per costruzione, $ s= j_1 $ è mappato su $ a_1 $ , fino a $ a_ \ ell $ fino ad alcuni offset. Ma abbiamo anche $ x \ in j_p $ , ciò implica un determinato periodo inferiore a $ \ ell \ le n / 4 $ in $ a '$ , che contraddice $ \ tau (A')> n / 3 $ . (Ci sono alcuni dettagli che aggiungerò più tardi)

Complessità complessiva Ad ogni fase della ricorsione, paghiamo $ o (m) $ . La periodicità $ \ tau (a) $ può anche essere calcolato in $ o (n) $ , da In calcolo del suffisso più lungo che è anche prefisso, di $ \ mathrm {diff} (a) $ , cioè l'array di incremento $ A_2-A_1, \ DOTS, A_N-A_ {N-1} $ . Tuttavia, la dimensione del problema si riduce per almeno $ 1/2 $ in ogni fase ricorsiva. Ci sarà $ \ log n $ passi nel caso peggiore, il che implica la complessità del tempo è delimitata da $ o (m \ log n) $ . Aggiunta dei costi di ordinamento, e poiché $ M> N $ , la complessità complessiva è delimitata dal tempo di smistamento $ o (m \ log m) $

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a cs.stackexchange
scroll top