Intervista: controlla se una stringa è una rotazione di un'altra stringa [chiusa]


235

Ad un mio amico è stata posta la seguente domanda oggi durante l'intervista per la posizione di sviluppatore di software:

Dato due stringhe s1e s2come controllerai se s1è una versione ruotata di s2?

Esempio:

Se s1 = "stackoverflow"quindi le seguenti sono alcune delle sue versioni ruotate:

"tackoverflows"
"ackoverflowst"
"overflowstack"

dove as non"stackoverflwo" è una versione ruotata.

La risposta che ha dato è stata:

Prendi s2e trova il prefisso più lungo che è una sottostringa di s1, che ti darà il punto di rotazione. Una volta trovato quel punto, rompi s2a quel punto per ottenere s2ae s2b, quindi controlla solo seconcatenate(s2a,s2b) == s1

Sembra una buona soluzione per me e il mio amico. Ma l'intervistatore ha pensato diversamente. Ha chiesto una soluzione più semplice. Ti prego, aiutami dicendo come faresti Java/C/C++?

Grazie in anticipo.


4
Non devi controllare se concatenare (s2a, s2b) == s1, perché sai che s2a è uguale all'inizio di s1. Puoi semplicemente verificare se s2b == sottostringa di s1 da punto_rotazione alla fine.
Jason Hall,

33
In che modo queste domande e la risposta migliore hanno ottenuto così tanti voti !?
David Johnstone,

9
@ David: Perché è interessante.
Cam

6
Direi, molto interessante e una risposta semplice ed elegante.
Guru,

7
@David: perché è una domanda che non è stata posta qui prima e che anche tutti capiscono (se uno non capisce la domanda / risposta, di solito non la classificherebbe; una domanda piuttosto semplice ha un pubblico più ampio) e anche perché questo è stato taggato con Java e C. Conta :)
BalusC

Risposte:


687

Prima assicurati s1che s2abbiano la stessa lunghezza. Quindi controlla se s2è una sottostringa di s1concatenata con s1:

algorithm checkRotation(string s1, string s2) 
  if( len(s1) != len(s2))
    return false
  if( substring(s2,concat(s1,s1))
    return true
  return false
end

In Java:

boolean isRotation(String s1,String s2) {
    return (s1.length() == s2.length()) && ((s1+s1).indexOf(s2) != -1);
}

49
Mi piace la sua eleganza, ma ho dovuto pensare un po 'per verificare che non ci fossero falsi positivi. (Non credo ci siano.)
Jon Skeet,

6
Puoi anche usarlo (s1+s1).contains(s2)in Java.
poligenelubrificanti

4
Comunque mi opporrei un po 'a questo come una domanda di intervista. Ha un "aha!" componente, penso. La maggior parte dei programmatori (me compreso) userebbe solo la forza bruta, che non è comunque irragionevole e che potrebbe sembrare non "abbastanza intelligente" per l'intervistatore.
Daniel Daranas,

5
@Jon Concentrate on s1+s1. Chiaramente, tutte le sue sottostringhe con dimensioni s1.lengthsono rotazioni di s1, per costruzione. Pertanto, qualsiasi stringa di dimensioni s1.lengthche è una sottostringa di s1+s1deve essere una rotazione di s1.
Daniel C. Sobral,

6
@unicornaddict - la cosa bella di questa soluzione è che è così ovvio una volta che me lo fai notare, mi odio per non averci pensato!
James B,

101

Sicuramente una risposta migliore sarebbe: "Beh, chiederei alla comunità di StackOverflow e probabilmente avrei almeno 4 risposte davvero buone in 5 minuti". I cervelli sono buoni e tutti, ma darei un valore più alto a qualcuno che sa come lavorare con gli altri per ottenere una soluzione.


14
+1 per la guancia pura. Ha reso la mia giornata :-)
Platinum Azure

5
Se non fossero d'accordo, potresti collegarli a questa domanda.
Cam

51
Tirare fuori il tuo cellulare durante un'intervista potrebbe essere considerato maleducato e alla fine finirebbero per assumere Jon Skeet.
Tstenner,

2
Questo in realtà probabilmente è esattamente quello che avrei detto
Chris Dutrow il

6
Non credo che potranno permettersi Jon Skeet.
SolutionYogi,

49

Un altro esempio di Python (basato sulla risposta):

def isrotation(s1,s2):
     return len(s1)==len(s2) and s1 in 2*s2

1
È interessante notare che ho pensato di duplicare s2piuttosto che s1troppo ... poi ho capito che la relazione era comunque simmetrica.
Matthieu M.

1
Se la stringa potrebbe essere lunga, ecco una versione di Python che utilizza Boyer-Moore per ottenere O (n) tempo di esecuzione: def isrotation (s1, s2): return len (s1) == len (s2) e re.compile (re .escape (s1)). search (2 * s2) non è None
Duncan

2
@Duncan: l' inoperatore non utilizza un algoritmo O (n)?
Ken Bloom,

1
@Duncan: i metodi delle stringhe in pitone usano un Boyer-Moore-Horspool ottimizzato. Mi chiedo se Java abbia ottimizzazioni simili.
Thomas Ahle,

1
@Thomas grazie per averlo sottolineato. Pensavo che solo le espressioni regolari usassero Boyer-Moore, ma vedo che mi sbagliavo. Per Python 2.4 e precedenti la mia risposta era corretta ma poiché Python 2.5 s1 in s2è ottimizzato. Vedi effbot.org/zone/stringlib.htm per la descrizione dell'algoritmo. Google sembra indicare che Java non ha una ricerca veloce delle stringhe (vedi johannburkard.de/software/stringsearch per esempio) anche se dubito che si spezzerebbe qualcosa se lo cambiassero.
Duncan,

32

Dato che altri hanno presentato una soluzione quadratica di complessità nel caso peggiore, ne aggiungerei una lineare (basata sull'algoritmo KMP ):

bool is_rotation(const string& str1, const string& str2)
{
  if(str1.size()!=str2.size())
    return false;

  vector<size_t> prefixes(str1.size(), 0);
  for(size_t i=1, j=0; i<str1.size(); i++) {
    while(j>0 && str1[i]!=str1[j])
      j=prefixes[j-1];
    if(str1[i]==str1[j]) j++;
    prefixes[i]=j;
  }

  size_t i=0, j=0;
  for(; i<str2.size(); i++) {
    while(j>0 && str2[i]!=str1[j])
      j=prefixes[j-1];
    if(str2[i]==str1[j]) j++;
  }
  for(i=0; i<str2.size(); i++) {
    if(j>=str1.size()) return true;
    while(j>0 && str2[i]!=str1[j])
      j=prefixes[j-1];
    if(str2[i]==str1[j]) j++;
  }

  return false;
}

esempio funzionante


5
+1 per ideone.com - sembra molto interessante!
Martin Vseticka,

25

EDIT: la risposta accettata è chiaramente più elegante ed efficiente di così, se la vedi. Ho lasciato questa risposta come quella che farei se non avessi pensato di raddoppiare la stringa originale.


Lo farei solo forza bruta. Controllare prima la lunghezza, quindi provare ogni possibile offset di rotazione. Se nessuno di loro risolve il problema, restituisci false - in caso affermativo, restituisci true immediatamente.

Non è necessario concatenare in particolare - basta usare i puntatori (C) o gli indici (Java) e camminare entrambi lungo, uno in ciascuna stringa - a partire dall'inizio di una stringa e l'offset di rotazione del candidato corrente nella seconda stringa e avvolgendo dove necessario . Controlla l'uguaglianza dei caratteri in ogni punto della stringa. Se arrivi alla fine della prima stringa, hai finito.

Probabilmente sarebbe altrettanto facile concatenare, anche se probabilmente meno efficiente, almeno in Java.


8
+1: non abbiamo bisogno di soluzioni eleganti che funzionino in 3+ volte la soluzione più efficiente. Questo è C ... la micro-ottimizzazione è di rigore .
Stephen C

8
Intervistatore: Devo parlare, ma scommetto che questo ragazzo non sa programmare.
Humphrey Bogart,

8
@Beau: Se qualcuno vuole pensarlo, sono invitati a chiedermi il codice. Se qualcuno mi chiede "come farei qualcosa" di solito descrivo l'algoritmo piuttosto che saltare al codice.
Jon Skeet,

3
@Jon - Ho letto il commento di Beau come uno scherzo
oxbow_lakes

37
@Jon Era uno scherzo! L'intervistatore non intervista Jon Skeet, Jon Skeet lo intervista.
Humphrey Bogart,

17

Eccone uno che usa regex solo per divertimento:

boolean isRotation(String s1, String s2) {
   return (s1.length() == s2.length()) && (s1 + s2).matches("(.*)(.*)\\2\\1");
}

Puoi renderlo un po 'più semplice se puoi usare un carattere delimitatore speciale garantito per non trovarsi in nessuna delle stringhe.

boolean isRotation(String s1, String s2) {
   // neither string can contain "="
   return (s1 + "=" + s2).matches("(.*)(.*)=\\2\\1");
}

Puoi anche usare lookbehind con ripetizione finita invece:

boolean isRotation(String s1, String s2) {
   return (s1 + s2).matches(
      String.format("(.*)(.*)(?<=^.{%d})\\2\\1", s1.length())
   );
}

6
+1 per essere un maestro regex.
Chris Thornton,

-1 Per mettere le parole "regex" e "fun" nella stessa affermazione, senza modificare "fun" con "not" (solo scherzando, non ho votato in basso)
Binary Worrier

-3 per aver insinuato che le regex non sono divertenti.
manlycode

qualsiasi body plz può spiegare come ha funzionato questo regex "(. *) (. *) = \\ 2 \\ 1"!
mawia,

10

Whoa, whoa ... perché tutti sono così elettrizzati dalla O(n^2)risposta? Sono sicuro che qui possiamo fare di meglio. La risposta sopra include O(n)un'operazione in un O(n)ciclo (la sottostringa / indexOf della chiamata). Anche con un algoritmo di ricerca più efficiente; dire Boyer-Mooreo KMP, il caso peggiore è ancora O(n^2)con i duplicati.

Una O(n)risposta randomizzata è semplice; prendere un hash (come un'impronta digitale di Rabin) che supporta una O(1)finestra scorrevole; stringa di hash 1, quindi stringa di hash 2 e procedere a spostare la finestra per l'hash 1 intorno alla stringa e vedere se le funzioni di hash si scontrano.

Se immaginiamo che il caso peggiore sia qualcosa come "scansionare due filamenti di DNA", allora la probabilità di collisioni aumenta e questo probabilmente degenera in qualcosa come O(n^(1+e)) o qualcosa (solo indovinando qui).

Infine, c'è una O(nlogn)soluzione deterministica che ha una costante molto grande all'esterno. Fondamentalmente, l'idea è quella di prendere una convoluzione delle due stringhe. Il valore massimo della convoluzione sarà la differenza di rotazione (se ruotati); un O(n)controllo conferma. La cosa bella è che se ci sono due valori massimi uguali, allora entrambi sono anche valide soluzioni. Puoi fare la convoluzione con due FFT e un prodotto punto e un iFFT, quindi nlogn + nlogn + n + nlogn + n == O(nlogn).

Poiché non è possibile eseguire il pad con zero e non è possibile garantire che le stringhe abbiano una lunghezza di 2 ^ n, gli FFT non saranno quelli veloci; saranno quelli lenti, O(nlogn)ma comunque una costante molto più grande dell'algoritmo CT.

Detto questo, sono assolutamente sicuro al 100% che esista una O(n)soluzione deterministica qui, ma dannatamente se riesco a trovarla.


Il KMP sulla stringa concatenata con se stesso (fisicamente o virtualmente con a %stringsize) è garantito come tempo lineare.
Kragen Javier Sitaker,

+1 per Rabin-Karp. A differenza di KMP, utilizza uno spazio costante ed è più semplice da implementare. (È anche la prima risposta a cui ho pensato, in pochi secondi, che rende difficile vedere la risposta "giusta", perché questa è proprio lì ed è dolce.) La tua idea di convoluzione mi ricorda l'algoritmo di Shor - Mi chiedo se c'è un sublineare soluzione quantistica - ma ora sta diventando sciocco, giusto?
Darius Bacon,

1
RK non fornisce una soluzione O (n) deterministica e KMP è O (n) nello spazio che potrebbe essere indesiderabile. Cercare la ricerca di sottostringhe bidirezionale o SMOA che sono entrambe O (n) nel tempo e O (1) nello spazio. A proposito, glibc strstr usa Two Way, ma se concatenate le stringhe per usarle invece di usare% len, tornerete a O (n) nello spazio. :-)
R .. GitHub FERMA AIUTANDO ICE il

8

Pugno, assicurati che le 2 corde abbiano la stessa lunghezza. Quindi in C, puoi farlo con una semplice iterazione del puntatore.


int is_rotation(char* s1, char* s2)
{
  char *tmp1;
  char *tmp2;
  char *ref2;

  assert(s1 && s2);
  if ((s1 == s2) || (strcmp(s1, s2) == 0))
    return (1);
  if (strlen(s1) != strlen(s2))
    return (0);

  while (*s2)
    {
      tmp1 = s1;
      if ((ref2 = strchr(s2, *s1)) == NULL)
        return (0);
      tmp2 = ref2;
      while (*tmp1 && (*tmp1 == *tmp2))
        {
          ++tmp1;
          ++tmp2;
          if (*tmp2 == '\0')
            tmp2 = s2;
        }
      if (*tmp1 == '\0')
        return (1);
      else
        ++s2;
    }
  return (0);
}

19
Ah, C. Perché fare qualcosa in metà tempo e codice quando puoi farlo in C!
Humphrey Bogart,

11
+1 È scritto molto bene C. E per essere onesti, la domanda è taggata 'c'.
Nick Moore,

5
In questo codice hai camminato le stringhe almeno 2 se non 3 volte (in strlen e strcmp). Puoi salvare te stesso questo controllo e puoi mantenere quella logica nel tuo ciclo. Mentre esegui il loop, se il conteggio di un carattere di stringa è diverso dall'altro, esci dal loop. Conoscerai le lunghezze, come sai l'inizio e sai quando hai colpito il terminatore null.
Nasko,

12
@Beau Martinez - perché a volte i tempi di esecuzione sono più importanti dei tempi di sviluppo :-)
phkahler

2
@phkahler - Il fatto è che potrebbe essere più lento. Le funzioni di indice integrate nelle altre lingue utilizzano in genere un algoritmo di ricerca di stringhe veloci come Boyer-Moore, Rabin-Karp o Knuth-Morris-Pratt. È troppo ingenuo semplicemente reinventare tutto in C e supporre che sia più veloce.
Thomas Ahle,

8

Ecco un O(n)algoritmo in atto. Usa l' <operatore per gli elementi delle stringhe. Non è mio ovviamente. L'ho preso da qui (Il sito è in polacco. Mi sono imbattuto in esso una volta in passato e non riuscivo a trovare qualcosa del genere ora in inglese, quindi mostro quello che ho :)).

bool equiv_cyc(const string &u, const string &v)
{
    int n = u.length(), i = -1, j = -1, k;
    if (n != v.length()) return false;

    while( i<n-1 && j<n-1 )
    {
        k = 1;
        while(k<=n && u[(i+k)%n]==v[(j+k)%n]) k++;
        if (k>n) return true;
        if (u[(i+k)%n] > v[(j+k)%n]) i += k; else j += k;
    }
    return false;
}

+1 ... O (n) è solo sooooo molto più profonda da un comp-sci punto di vista di qualsiasi non O (n) soluzione :)
SyntaxT3rr0r

4
+1 per una soluzione che è ottimale nel tempo e quasi ottimale nella dimensione del codice (sia binaria che LoC). Questa risposta sarebbe ancora migliore con una spiegazione.
R .. GitHub smette di aiutare ICE il

Assolutamente sconcertante. Abbiamo bisogno di una spiegazione!
j_random_hacker,

7

Immagino sia meglio farlo in Java:

boolean isRotation(String s1,String s2) {
    return (s1.length() == s2.length()) && (s1+s1).contains(s2);
}

In Perl farei:

sub isRotation {
 my($string1,$string2) = @_;
 return length($string1) == length($string2) && ($string1.$string1)=~/$string2/;
}

o ancora meglio usando la funzione index anziché regex:

sub isRotation {
 my($string1,$string2) = @_;
 return length($string1) == length($string2) && index($string2,$string1.$string1) != -1;
}

1
Hai dimenticato \Qin /\Q$string2/.
Kragen Javier Sitaker,

3
\Qcita tutti i caratteri speciali in $string2. Senza di essa, .sarebbe considerata una rotazione di qualsiasi stringa di 1 carattere.
jackrabbit,

6

Non sono sicuro che questo sia il metodo più efficiente, ma potrebbe essere relativamente interessante : la trasformazione di Burrows-Wheeler . Secondo l'articolo del WP, tutte le rotazioni dell'input producono lo stesso output. Per applicazioni come la compressione questo non è desiderabile, quindi la rotazione originale è indicata (ad esempio da un indice; vedere l'articolo). Ma per un semplice confronto indipendente dalla rotazione, sembra ideale. Certo, non è necessariamente idealmente efficiente!


Poiché la trasformazione Burrows-Wheeler comporta il calcolo di tutte le rotazioni della stringa, sicuramente non sarà ottimale .. :-)
R .. GitHub FERMA AIUTANDO ICE il

6

Prendi ogni personaggio come un'ampiezza ed esegui una trasformata di Fourier discreta su di essi. Se differiscono solo per rotazione, gli spettri di frequenza saranno gli stessi all'interno dell'errore di arrotondamento. Naturalmente questo è inefficiente a meno che la lunghezza non sia una potenza di 2, quindi puoi fare una FFT :-)


Abbiamo usato questo come un interessante esercizio di codifica, non sono sicuro che saremo in grado di valutarlo;).
jayshao,

FFT abusato :) +1 da parte mia
Aamir

5

Nessuno ha ancora offerto un approccio al modulo, quindi eccone uno:

static void Main(string[] args)
{
    Console.WriteLine("Rotation : {0}",
        IsRotation("stackoverflow", "ztackoverflow"));
    Console.WriteLine("Rotation : {0}",
        IsRotation("stackoverflow", "ackoverflowst"));
    Console.WriteLine("Rotation : {0}",
        IsRotation("stackoverflow", "overflowstack"));
    Console.WriteLine("Rotation : {0}",
        IsRotation("stackoverflow", "stackoverflwo"));
    Console.WriteLine("Rotation : {0}",
        IsRotation("stackoverflow", "tackoverflwos"));
    Console.ReadLine();
}

public static bool IsRotation(string a, string b)
{
    Console.WriteLine("\nA: {0} B: {1}", a, b);

    if (b.Length != a.Length)
        return false;

    int ndx = a.IndexOf(b[0]);
    bool isRotation = true;
    Console.WriteLine("Ndx: {0}", ndx);
    if (ndx == -1) return false;
    for (int i = 0; i < b.Length; ++i)
    {
        int rotatedNdx = (i + ndx) % b.Length;
        char rotatedA = a[rotatedNdx];

        Console.WriteLine( "B: {0} A[{1}]: {2}", b[i], rotatedNdx, rotatedA );

        if (b[i] != rotatedA)
        {
            isRotation = false;
            // break; uncomment this when you remove the Console.WriteLine
        }
    }
    return isRotation;
}

Produzione:

A: stackoverflow B: ztackoverflow
Ndx: -1
Rotation : False

A: stackoverflow B: ackoverflowst
Ndx: 2
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: o A[11]: o
B: w A[12]: w
B: s A[0]: s
B: t A[1]: t
Rotation : True

A: stackoverflow B: overflowstack
Ndx: 5
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: o A[11]: o
B: w A[12]: w
B: s A[0]: s
B: t A[1]: t
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
Rotation : True

A: stackoverflow B: stackoverflwo
Ndx: 0
B: s A[0]: s
B: t A[1]: t
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: w A[11]: o
B: o A[12]: w
Rotation : False

A: stackoverflow B: tackoverflwos
Ndx: 1
B: t A[1]: t
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: w A[11]: o
B: o A[12]: w
B: s A[0]: s
Rotation : False

[MODIFICA: 12-04-2010]

piotr ha notato il difetto nel mio codice sopra. Si verifica un errore quando il primo carattere nella stringa appare due o più volte. Ad esempio, stackoverflowtestato contro ha owstackoverflowprovocato falso, quando dovrebbe essere vero.

Grazie piotr per aver individuato l'errore.

Ora, ecco il codice corretto:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace TestRotate
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "ztackoverflow"));
            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "ackoverflowst"));
            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "overflowstack"));
            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "stackoverflwo"));
            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "tackoverflwos"));

            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "owstackoverfl"));

            Console.ReadLine();
        }

        public static bool IsRotation(string a, string b)
        {
            Console.WriteLine("\nA: {0} B: {1}", a, b);

            if (b.Length != a.Length)
                return false;

            if (a.IndexOf(b[0]) == -1 )
                return false;

            foreach (int ndx in IndexList(a, b[0]))
            {
                bool isRotation = true;

                Console.WriteLine("Ndx: {0}", ndx);

                for (int i = 0; i < b.Length; ++i)
                {
                    int rotatedNdx = (i + ndx) % b.Length;
                    char rotatedA = a[rotatedNdx];

                    Console.WriteLine("B: {0} A[{1}]: {2}", b[i], rotatedNdx, rotatedA);

                    if (b[i] != rotatedA)
                    {
                        isRotation = false;
                        break;
                    }
                }
                if (isRotation)
                    return true;
            }
            return false;
        }

        public static IEnumerable<int> IndexList(string src, char c)
        {
            for (int i = 0; i < src.Length; ++i)
                if (src[i] == c)
                    yield return i;
        }

    }//class Program
}//namespace TestRotate

Ecco l'output:

A: stackoverflow B: ztackoverflow
Rotation : False

A: stackoverflow B: ackoverflowst
Ndx: 2
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: o A[11]: o
B: w A[12]: w
B: s A[0]: s
B: t A[1]: t
Rotation : True

A: stackoverflow B: overflowstack
Ndx: 5
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: o A[11]: o
B: w A[12]: w
B: s A[0]: s
B: t A[1]: t
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
Rotation : True

A: stackoverflow B: stackoverflwo
Ndx: 0
B: s A[0]: s
B: t A[1]: t
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: w A[11]: o
Rotation : False

A: stackoverflow B: tackoverflwos
Ndx: 1
B: t A[1]: t
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
B: w A[11]: o
Rotation : False

A: stackoverflow B: owstackoverfl
Ndx: 5
B: o A[5]: o
B: w A[6]: v
Ndx: 11
B: o A[11]: o
B: w A[12]: w
B: s A[0]: s
B: t A[1]: t
B: a A[2]: a
B: c A[3]: c
B: k A[4]: k
B: o A[5]: o
B: v A[6]: v
B: e A[7]: e
B: r A[8]: r
B: f A[9]: f
B: l A[10]: l
Rotation : True

Ecco l'approccio lambda:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IsRotation
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "ztackoverflow"));

            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "ackoverflowst"));

            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "overflowstack"));
            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "stackoverflwo"));

            Console.WriteLine("Rotation : {0}",
                IsRotation("stackoverflow", "owstackoverfl"));

            string strToTestFrom = "stackoverflow";
            foreach(string s in StringRotations(strToTestFrom))
            {
                Console.WriteLine("is {0} rotation of {1} ? {2}",
                    s, strToTestFrom,
                    IsRotation(strToTestFrom, s) );
            }
            Console.ReadLine();
        }

        public static IEnumerable<string> StringRotations(string src)
        {
            for (int i = 0; i < src.Length; ++i)
            {
                var sb = new StringBuilder();
                for (int x = 0; x < src.Length; ++x)
                    sb.Append(src[(i + x) % src.Length]);

                yield return sb.ToString();
            }
        }

        public static bool IsRotation(string a, string b)
        {
            if (b.Length != a.Length || a.IndexOf(b[0]) < 0 ) return false;
            foreach(int ndx in IndexList(a, b[0]))
            {
                int i = ndx;
                if (b.ToCharArray().All(x => x == a[i++ % a.Length]))
                    return true;
            }
            return false;
        }

        public static IEnumerable<int> IndexList(string src, char c)
        {
            for (int i = 0; i < src.Length; ++i)
                if (src[i] == c)
                    yield return i;
        }

    }//class Program

}//namespace IsRotation

Ecco l'output dell'approccio lambda:

Rotation : False
Rotation : True
Rotation : True
Rotation : False
Rotation : True
is stackoverflow rotation of stackoverflow ? True
is tackoverflows rotation of stackoverflow ? True
is ackoverflowst rotation of stackoverflow ? True
is ckoverflowsta rotation of stackoverflow ? True
is koverflowstac rotation of stackoverflow ? True
is overflowstack rotation of stackoverflow ? True
is verflowstacko rotation of stackoverflow ? True
is erflowstackov rotation of stackoverflow ? True
is rflowstackove rotation of stackoverflow ? True
is flowstackover rotation of stackoverflow ? True
is lowstackoverf rotation of stackoverflow ? True
is owstackoverfl rotation of stackoverflow ? True
is wstackoverflo rotation of stackoverflow ? True

Non credo che la tua risposta sia corretta poiché int ndx = a.IndexOf (b [0]); funzionerà solo se non ci sono altri elementi con lo stesso valore di b [0] nella stringa.
piotr,

grazie per aver notato il difetto. corretto ora
Michael Buen,

3

Poiché nessuno ha fornito una soluzione C ++. eccolo qui:

bool isRotation(string s1,string s2) {

  string temp = s1;
  temp += s1;
  return (s1.length() == s2.length()) && (temp.find(s2) != string::npos);
}

Coppia punti: stai concatenando la stringa relativamente costosa anche se le lunghezze non corrispondono; potresti passare s2 per riferimento const.
Tony Delroy,

2

Il semplice trucco di rotazione del puntatore di Opera funziona, ma è estremamente inefficiente nel peggiore dei casi in fase di esecuzione. Immagina semplicemente una stringa con molte sequenze di caratteri lunghe e ripetitive, ovvero:

S1 = HELLOHELLOHELLO1HELLOHELLOHELLO2

S2 = HELLOHELLOHELLO2HELLOHELLOHELLO1

Il "ciclo fino a quando non c'è una discrepanza, quindi incrementa di uno e riprova" è un approccio orribile, a livello computazionale.

Per dimostrare che è possibile eseguire l'approccio di concatenazione nella pianura C senza troppi sforzi, ecco la mia soluzione:

  int isRotation(const char* s1, const char* s2) {
        assert(s1 && s2);

        size_t s1Len = strlen(s1);

        if (s1Len != strlen(s2)) return 0;

        char s1SelfConcat[ 2 * s1Len + 1 ];

        sprintf(s1SelfConcat, "%s%s", s1, s1);   

        return (strstr(s1SelfConcat, s2) ? 1 : 0);
}

Questo è lineare nel tempo di esecuzione, a scapito dell'utilizzo della memoria O (n) in sovraccarico.

(Si noti che l'implementazione di strstr () è specifica per la piattaforma, ma se particolarmente cerebrale, può sempre essere sostituita con un'alternativa più veloce come l'algoritmo di Boyer-Moore)


1
Conosci qualche piattaforma che ha strstr()in O (n + m)? Inoltre, se lo standard (o qualsiasi altra cosa) non ti garantisce un tempo di esecuzione lineare di strstr(), non puoi affermare che l'intero algoritmo ha una compattezza temporale lineare.
jpalecek,

Ecco perché ho detto che può essere sostituito dall'algoritmo Boyer-Moore, facendolo funzionare in tempo lineare.
RarrRarrRarr

Ci sono un paio di potenziali problemi con il tuo metodo di allocazione s1SelfConcat: è solo dal momento che C9x che C consente dimensioni di array variabili (anche se GCC lo ha permesso molto più a lungo), e potresti riscontrare problemi nell'allocare grandi stringhe nello stack. Yosef Kreinin ha scritto un post sul blog molto divertente su questo problema. Inoltre, la tua soluzione è ancora quadratica con Boyer-Moore; vuoi KMP.
Kragen Javier Sitaker,


2

Mi piace LA risposta che controlla se s2 è una sottostringa di s1 concatenata con s1.

Volevo aggiungere un'ottimizzazione che non perda la sua eleganza.

Invece di concatenare le stringhe è possibile utilizzare una visualizzazione join (non lo so per altre lingue, ma per C ++ Boost.Range fornire questo tipo di visualizzazioni).

Poiché il controllo se una stringa è una sottostringa di un'altra ha una complessità media lineare (la complessità del caso peggiore è quadratica), questa ottimizzazione dovrebbe migliorare la velocità di un fattore 2 in media.


2

Una risposta Java pura (senza controlli null)

private boolean isRotation(String s1,String s2){
    if(s1.length() != s2.length()) return false;
    for(int i=0; i < s1.length()-1; i++){
        s1 = new StringBuilder(s1.substring(1)).append(s1.charAt(0)).toString();
        //--or-- s1 = s1.substring(1) + s1.charAt(0)
        if(s1.equals(s2)) return true;
    }
    return false;
}

2

E ora qualcosa di completamente diverso.

Se si desidera una risposta molto rapida in un contesto limitato quando le stringhe non sono ruotate l'una rispetto all'altra

  • calcola un checksum basato sui caratteri (come xorare tutti i caratteri) su entrambe le stringhe. Se le firme differiscono, le stringhe non sono rotazioni l'una dell'altra.

D'accordo, può fallire, ma è molto veloce dire se le stringhe non corrispondono e se corrispondono puoi comunque usare un altro algoritmo come la concatenazione delle stringhe per verificare.


1

Un'altra soluzione Rubino sulla base della risposta:

def rotation?(a, b); a.size == b.size and (b*2)[a]; end

1

È molto facile scrivere in PHP usando strlene le strposfunzioni:

function isRotation($string1, $string2) {
    return strlen($string1) == strlen($string2) && (($string1.$string1).strpos($string2) != -1);
}

Non so cosa strposusi internamente, ma se usa KMP questo sarà lineare nel tempo.


1

Invertire una delle stringhe. Prendi la FFT di entrambi (trattandoli come semplici sequenze di numeri interi). Moltiplica i risultati insieme in modo puntuale. Trasforma indietro usando FFT inversa. Il risultato avrà un singolo picco se le stringhe sono rotazioni l'una dell'altra - la posizione del picco indicherà quanto vengono ruotate l'una rispetto all'altra.


0

Perché non qualcosa del genere?


//is q a rotation of p?
bool isRotation(string p, string q) {
    string table = q + q;    
    return table.IndexOf(p) != -1;
}

Ovviamente, potresti scrivere la tua funzione IndexOf (); Non sono sicuro che .NET usi un modo ingenuo o più veloce.

Ingenuo:


int IndexOf(string s) {
    for (int i = 0; i < this.Length - s.Length; i++)
        if (this.Substring(i, s.Length) == s) return i;
    return -1;
}

Più veloce:


int IndexOf(string s) {
    int count = 0;
    for (int i = 0; i < this.Length; i++) {
        if (this[i] == s[count])
            count++;
        else
            count = 0;
        if (count == s.Length)
            return i - s.Length;
    }
    return -1;
}

Modifica: potrei avere alcuni problemi specifici; non ho voglia di controllare. ;)


0

Lo farei in Perl :

sub isRotation { 
     return length $_[0] == length $_[1] and index($_[1],$_[0],$_[0]) != -1; 
}

0
int rotation(char *s1,char *s2)
{
    int i,j,k,p=0,n;
    n=strlen(s1);
    k=strlen(s2);
    if (n!=k)
        return 0;
    for (i=0;i<n;i++)
    {
        if (s1[0]==s2[i])
        {
            for (j=i,k=0;k<n;k++,j++)
            {
                if (s1[k]==s2[j])
                    p++;
                if (j==n-1)
                    j=0;
            }
        }
    }
    if (n==p+1)
      return 1;
    else
      return 0;
}

0

Partecipa string1con string2e utilizzare l'algoritmo KMP per verificare se string2è presente nella stringa di recente formazione. Perché la complessità temporale di KMP è inferiore a substr.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.