Röportaj sorusu: Bir dizenin diğer dizenin rotasyonu olup olmadığını kontrol edin [kapalı]


235

Bir arkadaşımdan, yazılım geliştiricisinin pozisyonu için röportajda şu soru soruldu:

İki dize göz önüne alındığında s1ve s2nasıl kontrol edecek s1bir olduğunu döndürülmüş sürümü s2?

Misal:

Öyleyse s1 = "stackoverflow", aşağıdakiler döndürülmüş sürümlerinden bazılarıdır:

"tackoverflows"
"ackoverflowst"
"overflowstack"

nerede olarak "stackoverflwo"ise değil döndürülmüş sürümü.

Verdiği cevap şuydu:

Size dönme noktasını verecek s2olan alt dizesi olan en uzun öneki alın ve bulun s1. Bu noktayı bulduğunuzda, s2almak için o noktayı kırın s2ave s2bsonra sadececoncatenate(s2a,s2b) == s1

Ben ve arkadaşım için iyi bir çözüm gibi görünüyor. Ancak görüşmeci başka türlü düşündü. Daha basit bir çözüm istedi. Eğer bunu nasıl anlatarak Lütfen bana yardım Java/C/C++?

Şimdiden teşekkürler.


4
Birleştirme (s2a, s2b) == s1 olup olmadığını kontrol etmek zorunda değilsiniz, çünkü s2a'nın s1'in başına eşit olduğunu biliyorsunuz. Sadece s2b == s1 alt dizgesinin rotation_point'ten ende olup olmadığını kontrol edebilirsiniz.
Jason Hall

33
Bu sorular ve en iyi cevap nasıl bu kadar çok oy aldı?
David Johnstone

9
@David: Çünkü ilginç.
Cam

6
Çok ilginç ve zarif, basit bir cevap diyebilirim.
Guru

7
@David: çünkü burada daha önce sorulmayan ve aynı zamanda herkesin anladığı bir soru (eğer kişi soru / cevabı anlamıyorsa, genellikle emin olamayız; oldukça basit bir soru daha geniş bir kitleye sahiptir) ve ayrıca çünkü bu hem Java hem de C ile etiketlendi.
Önemli

Yanıtlar:


687

Öncelikle emin olun s1ve s2aynı uzunluktadır. Ardından s2, s1birleştirilmiş bir alt dizenin olup olmadığını kontrol edin 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

Java dilinde:

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

49
Onun zarafetini seviyorum, ama yanlış pozitif olmadığını kontrol etmek için bir süre düşünmek zorunda kaldım. (Ben olduğunu sanmıyorum .)
Jon Skeet

6
(s1+s1).contains(s2)Java ile de kullanabilirsiniz .
poligenelubrikantlar

4
Her neyse, buna röportaj sorusu olarak biraz itiraz ederim. Bir "aha!" bence. Çoğu programcı (ben dahil), sadece mantıksız olmayan kaba kuvvet kullanacaktı ve bu, görüşmeci için yeterince "akıllı" görünmeyebilir.
Daniel Daranas

5
@ Jon Konsantre s1+s1. Açıkçası, boyutuna sahip tüm alt telleri yapı s1.lengtholarak rotasyonlardır s1. Bu nedenle, s1.lengthalt dizesi olan herhangi bir boyut dizesi s1+s1bir döndürme olmalıdır s1.
Daniel C.Sobral

6
@ unicornaddict - bu çözümün en güzel yanı, bir kez işaret ettiğinizde çok açık olması, onu düşünmediğim için kendimden nefret ediyorum!
James B

101

Şüphesiz daha iyi bir cevap, "Şey, stackoverflow topluluğuna sorardım ve muhtemelen 5 dakika içinde en az 4 gerçekten iyi cevabı olurdu" olurdu. Beyinler iyi ve hepsi, ama bir çözüm elde etmek için başkalarıyla nasıl çalışacağını bilen birine daha yüksek bir değer verirdim.


14
Şeffaf yanak için +1. Made my day :-)
Platinum Azure

5
Eğer katılmazlarsa, onları bu soruya bağlayabilirsiniz.
Cam

51
Bir röportaj sırasında cep telefonunuzu kırmak kaba kabul edilebilir ve sonunda Jon Skeet'i işe alırlardı.
tstenner

2
Bu muhtemelen tam olarak ne söylerdim
Chris Dutrow

6
Jon Skeet'i karşılayabileceklerini sanmıyorum.
SolutionYogi

49

Başka bir python örneği (cevaba dayalı olarak):

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

1
İlginç bir şekilde çoğaltmak s2yerine çoğaltmayı düşündüm s1... sonra ilişkinin yine de simetrik olduğunu fark ettim.
Matthieu M.11

1
Dize uzun olabilirse, O (n) çalışma süresini elde etmek için Boyer-Moore kullanan bir Python sürümü: def isrotation (s1, s2): return len (s1) == len (s2) ve re.compile (re .escape (s1)). arama (2 * s2) Yok
Duncan

2
@Duncan: inOperatör bir O (n) algoritması kullanmıyor mu?
Ken Bloom

1
@Duncan: Python string yöntemleri optimize edilmiş bir Boyer-Moore-Horspool kullanıyor. Java'nın benzer optimizasyonlara sahip olup olmadığını merak ediyorum.
Thomas Ahle

1
@Thomas bunu işaret ettiğiniz için teşekkürler. Sadece düzenli ifadelerin Boyer-Moore kullandığını düşünmüştüm ama yanıldığımı görüyorum. Python 2.4 ve öncesi için cevabım doğruydu ama Python 2.5 s1 in s2optimize edildiğinden. Algoritmanın açıklaması için effbot.org/zone/stringlib.htm adresine bakın . Google, Java'nın hızlı dize araması olmadığını ( örneğin, bkz. Johannburkard.de/software/stringsearch ) olmadığını belirtmiş gibi görünüyor, ancak değiştirdikleri takdirde herhangi bir şeyi kıracağından şüpheliyim.
Duncan

32

Diğerleri ikinci dereceden en kötü durum karmaşıklığı çözümü sunduğundan, doğrusal bir çözüm eklerdim ( KMP Algoritmasına dayanarak ):

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;
}

çalışma örneği


5
İdeone.com için +1 - çok ilginç görünüyor!
Martin Vseticka

25

DÜZENLEME: Kabul ettiğiniz cevap, açıkça fark ederseniz, bundan daha zarif ve etkilidir. Orijinal cevabı iki katına çıkarmayı düşünmemiş olsaydım bu cevabı ne yapacağımı bıraktım.


Sadece kaba kuvvet isterdim. Önce uzunluğu kontrol edin ve sonra olası her dönüş ofsetini deneyin. Hiçbiri işe yaramazsa false değerini döndürün - eğer herhangi biri işe yaramazsa hemen true değerini döndürün.

Birleştirmeye gerek yoktur - sadece işaretçileri (C) veya dizinleri (Java) kullanın ve her dizede bir tane olmak üzere her ikisinde de yürüyün - bir dizenin başlangıcından başlayarak ikinci dizede geçerli aday döndürme ofsetini ve gerektiğinde sarma . Dizedeki her noktada karakter eşitliğini kontrol edin. İlk dizenin sonuna gelirseniz işiniz bitmiştir.

Muhtemelen daha az verimli olsa da, en azından Java'da birleştirmek yaklaşık olarak kolay olacaktır.


8
+1 - en verimli çözümün 3 + katında çalışan zarif çözümlere ihtiyacımız yok. Bu C ... mikro-optimizasyon de riguer olduğunu .
Stephen C

8
Röportajcı: Lotta konuşur, ama bahse girerim bu adam kod yazamaz.
Humphrey Bogart

8
@Beau: Eğer birisi bunu düşünmek isterse, benden kod isteyebilirsin. Birisi bana sadece "nasıl bir şey yaparım" diye sorarsa ben genellikle kod atlamak yerine algoritma açıklar.
Jon Skeet

3
@Jon - Beau'nun bir şaka olarak yorumu okudum
oxbow_lakes

37
@Jon Şakaydı! Görüşmeci Jon Skeet ile röportaj yapmaz, Jon Skeet onunla röportaj yapar.
Humphrey Bogart

17

İşte sadece eğlence için regex kullanan biri:

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

Her iki dizede de bulunmadığı garanti edilen özel bir sınırlayıcı karakter kullanabiliyorsanız bunu biraz daha basit hale getirebilirsiniz.

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

Bunun yerine lookbehind'i sonlu yineleme ile de kullanabilirsiniz:

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

6
Normal ifade ustası olduğu için +1.
Chris Thornton

-1 "regex" ve "fun" kelimelerini aynı ifadeye, "fun" kelimesini "not" ile değiştirmeden koymak için (sadece şaka, ben oy kullanmadım)
İkili Worrier

Normal ifadelerin eğlenceli olmadığını ima ettiği için -3.
manlycode

herhangi bir vücut plz bu normal ifade "(. *) (. *) = \\ 2 \\ 1" nasıl çalıştığını açıklayabilir!
mawia

10

Vay, vay ... neden herkes bir O(n^2)cevapla bu kadar heyecanlı ? Burada daha iyisini yapabileceğimizden eminim. Yukarıdaki cevap O(n), bir O(n)döngüdeki bir işlemi (alt dize / indexOf çağrısı) içerir. Daha verimli bir arama algoritmasıyla bile; demek Boyer-Mooreya KMPkötü durum hala, O(n^2)tekrarlar da.

Bir O(n)randomize cevap basittir; O(1)sürgülü pencereyi destekleyen bir karma (Rabin parmak izi gibi) alın; hash string 1, sonra hash string 2'yi seçin ve hash 1 için pencereyi dizenin etrafında hareket ettirin ve hash işlevlerinin çarpışıp çarpışmadığına bakın.

En kötü durumun "iki DNA dizisini taramak" gibi bir şey olduğunu hayal edersek, çarpışma olasılığı artar ve bu muhtemelen böyle bir O(n^(1+e))şeye ya da bir şeye (sadece tahmin ederek) yozlaşır.

Son olarak, O(nlogn)dışında çok büyük bir sabiti olan deterministik bir çözüm var. Temel olarak, fikir iki telin bir evrişimini almaktır. Evrişimin maksimum değeri dönme farkı olacaktır (eğer döndürülmüşlerse); bir O(n)onay teyit eder. Güzel olan şey, iki eşit maksimum değer varsa, her ikisinin de geçerli çözümler olmasıdır. Evrişimi iki FFT ve bir nokta ürünü ve bir iFFT ile yapabilirsiniz nlogn + nlogn + n + nlogn + n == O(nlogn).

Sıfırlarla dolgu yapamayacağınız ve dizelerin 2 ^ n uzunluğunda olduğunu garanti edemeyeceğiniz için, FFT'ler hızlı olanlar olmayacaktır; O(nlogn)BT algoritmasından daha yavaş ama yine de çok daha büyük bir sabit olacaklardır .

Bütün bunlar, kesinlikle,% 100 pozitif, burada deterministik bir O(n)çözüm olduğunu söyledi, ancak bulabilirsem karartıyorum.


Kendisiyle birleştirilmiş dize (fiziksel veya sanal olarak a ile %stringsize) üzerindeki KMP'nin doğrusal zaman olması garanti edilir.
Kragen Javier Sitaker

Rabin-Karp için +1. KMP'den farklı olarak, sabit alan kullanır ve uygulanması daha kolaydır. (Ayrıca düşündüğüm ilk cevap saniyeler içinde 'doğru' cevabı görmeyi zorlaştırıyor, çünkü bu tam orada ve tatlı.) Evrişim fikriniz bana Shor'un algoritmasını hatırlatıyor - bir alt çizginin olup olmadığını merak ediyorum kuantum çözümü - ama şimdi aptalca oluyor, değil mi?
Darius Bacon

1
RK, deterministik bir O (n) çözeltisi vermez ve KMP, uzayda istenmeyen olabilecek O (n) 'dir. Zaman içinde O (n) ve uzayda O (1) olan İki Yönlü veya SMOA alt dize aramasına bakın. Bu arada, glibc strstr İki Yol kullanır, ancak dizeleri% len kullanmak yerine kullanmak için birleştirirseniz, uzayda O (n) 'ye geri dönersiniz. :-)
R .. GitHub DUR YARDIMCI ICE

8

Yumruk, 2 telin aynı uzunlukta olduğundan emin olun. Daha sonra C'de bunu basit bir işaretçi yinelemesi ile yapabilirsiniz.


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. Neden C ile yapabileceğin zamanın yarısında bir şeyler yapıyorsun?
Humphrey Bogart

11
+1 Çok iyi yazılmış. C. Ve adil olmak gerekirse, soru 'c' olarak etiketlendi.
Nick Moore

5
Bu kodda 3 kez değilse dizeleri en az 2 kez yürüdünüz (strlen ve strcmp'de). Bu kontrolü kendinize kaydedebilir ve bu mantığı döngünüzde tutabilirsiniz. Döngü yaparken, bir dize karakter sayısı diğerinden farklıysa, döngüden çıkın. Başlıkları bildiğiniz gibi uzunlukları bileceksiniz ve boş sonlandırıcıya ne zaman vurduğunuzu biliyorsunuz.
Nasko

12
@Beau Martinez - çünkü bazen yürütme süresi geliştirme süresinden daha önemlidir :-)
phkahler

2
@phkahler - Mesele şu ki, daha yavaş olabilir. Diğer dillerde yerleşik indeks fonksiyonları tipik olarak Boyer-Moore, Rabin-Karp veya Knuth-Morris-Pratt gibi bir hızlı dize arama algoritması kullanır. Çok saf, sadece C'deki her şeyi yeniden icat edin ve daha hızlı olduğunu varsayın.
Thomas Ahle

8

İşte bir O(n)ve yerinde alghoritm. <Dizelerin elemanları için operatör kullanır . Tabii ki benim değil. Buradan aldım (Site lehçedir. Geçmişte bir kez tökezledim ve şimdi İngilizce olarak böyle bir şey bulamadım, bu yüzden sahip olduğum şeyi göster :)).

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) hemen bir sooooo çok daha büyük bir mesafede abone-Sci olmayan herhangi bir fazla bakış O (n) :) çözeltisi
SyntaxT3rr0r

4
Zaman içinde ve kod boyutunda (hem ikili hem de LoC) en uygun olan çözüm için +1. Bu cevap bir açıklama ile daha da iyi olurdu.
R .. GitHub BUZA YARDIMCI OLDU

Tamamen şaşırtıcı. Bir açıklamaya ihtiyacımız var!
j_random_hacker

7

Sanırım bunu yapmak daha iyi Java:

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

Perl'de yapardım:

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

veya regex yerine index işlevini kullanmak daha da iyidir :

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

1
Sen unuttun \Qiçinde /\Q$string2/.
Kragen Javier Sitaker

3
\Qiçindeki tüm özel karakterleri tırnak içine alır $string2. Onsuz ., herhangi bir 1 karakterli dizenin dönüşü olarak kabul edilir.
jackrabbit

6

Bunun en etkili yöntem olup olmadığından emin değilim, ancak nispeten ilginç olabilir : Burrows-Wheeler dönüşümü . WP makalesine göre, girdinin tüm rotasyonları aynı çıktıyı verir. Sıkıştırma gibi uygulamalar için bu arzu edilmez, bu nedenle orijinal döndürme gösterilir (örneğin bir indeks ile; makaleye bakın). Ancak, rotasyondan bağımsız basit karşılaştırma için, kulağa ideal geliyor. Tabii ki, mutlaka ideal olarak verimli değildir!


Burrows-Wheeler dönüşümü ipin tüm rotasyonlarını hesaplamayı içerdiğinden, kesinlikle optimal olmayacaktır .. :-)
R .. GitHub DURDURMAK BUZ

6

Her karakteri bir genlik olarak alın ve üzerlerinde ayrı bir Fourier dönüşümü gerçekleştirin. Sadece döndürme ile farklılık gösterirlerse, frekans spektrumu yuvarlama hatasıyla aynı olacaktır. Tabii ki bu uzunluk 2'nin gücü olmadığı sürece verimsizdir, böylece bir FFT yapabilirsiniz :-)


Bunu ilginç bir kodlama egzersizi olarak kullandık, bunu değerlendirebileceğimizden emin değilim;).
jayshao

FFT istismar :) Benden +1
Aamir

5

Henüz kimse modulo yaklaşımı önermedi, işte burada:

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;
}

Çıktı:

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

[DÜZENLEME: 2010-04-12]

piotr yukarıdaki kodumdaki kusuru fark etti. Dizedeki ilk karakter iki veya daha fazla kez oluştuğunda hata verir. Örneğin, stackoverflowtest owstackoverflowedilmesi, doğru olması gerektiğinde yanlış ile sonuçlandı.

Hatayı tespit ettiğiniz için teşekkürler piotr.

Şimdi, burada düzeltilmiş kod:

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

İşte çıktı:

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

İşte lambda yaklaşımı:

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

İşte lambda yaklaşımı çıktısı:

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

Ben int ndx = a.IndexOf (b [0]) beri cevabınızın doğru olduğunu düşünmüyorum; yalnızca dizede aynı [b] değerine sahip başka öğe yoksa çalışır.
piotr

kusuru fark ettiğiniz için teşekkürler. düzeltildi
Michael Buen

3

Kimse bir C ++ çözümü vermediğinden. işte burada:

bool isRotation(string s1,string s2) {

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

Çift puan: uzunluklar eşleşmese bile nispeten pahalı dize birleştirmesini yapıyorsunuz; const referansı ile s2'yi geçebilirsiniz.
Tony Delroy

2

Opera'nın basit işaretçi döndürme hilesi çalışır, ancak çalışma süresindeki en kötü durumda son derece verimsizdir. Birçok uzun tekrarlayan karakter dizisine sahip bir dize düşünün, yani:

S1 = HELLOHELLOHELLO1HELLOHELLOHELLO2

S2 = HELLOHELLOHELLO2HELLOHELLOHELLO1

"Bir uyumsuzluk olana kadar döngü, daha sonra birer birer artır ve tekrar dene", hesaplama açısından korkunç bir yaklaşımdır.

Çok fazla çaba harcamadan düz C'de birleştirme yaklaşımını yapabileceğinizi kanıtlamak için işte benim çözümüm:

  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);
}

Bu, çalışma süresinde, ek yükte O (n) bellek kullanımı pahasına doğrusaldır.

(Strstr () uygulamasının platforma özgü olduğunu, ancak özellikle beyin ölüsünde, her zaman Boyer-Moore algoritması gibi daha hızlı bir alternatifle değiştirilebileceğini unutmayın)


1
strstr()O (n + m) 'da olan herhangi bir platform biliyor musunuz ? Ayrıca, standart (veya başka herhangi bir şey) size doğrusal bir çalışma süresi garanti etmezse strstr(), tüm algoritmanın doğrusal zaman karmaşıklığına sahip olduğunu iddia edemezsiniz.
jpalecek

Bu yüzden onun yerine Boyer-Moore algoritması ile değiştirilebileceğini söyledim, bu da lineer zamanda çalışmasını sağladı.
RarrRarrRarr

Tahsis yönteminizle ilgili birkaç potansiyel sorun vardır s1SelfConcat: sadece C9x'ten beri C değişken dizi boyutlarına izin verir (GCC buna daha uzun süre izin vermesine rağmen) ve yığın üzerinde büyük dizeler tahsis etmekte sorun yaşarsınız. Yosef Kreinin, bu sorun hakkında çok eğlenceli bir blog yazısı yazdı . Ayrıca, çözümünüz Boyer-Moore ile hala ikinci dereceden zaman; KMP istiyorum.
Kragen Javier Sitaker


2

Ben s2 s1 ile birleştirilmiş s1 bir alt dizesi olup olmadığını denetler cevap gibi.

Zerafetini kaybetmeyen bir optimizasyon eklemek istedim.

Dizeleri birleştirmek yerine birleştirme görünümü kullanabilirsiniz (diğer dil için bilmiyorum, ancak C ++ Boost.Range için bu tür görünümler sağlar).

Bir dizginin bir diğerinin alt dizesi olup olmadığını kontrol etmenin lineer ortalama karmaşıklığı (En kötü durum karmaşıklığı ikinci derecelidir) olduğundan, bu optimizasyon hızı ortalama 2 faktör artırmalıdır.


2

Saf bir Java yanıtı (boş denetimleri sans)

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

Ve şimdi tamamen farklı bir şey.

Dizeler birbirinin dönüşü olmadığında bazı kısıtlı bağlamda gerçekten hızlı bir cevap istiyorsanız

  • her iki dizede de karakter tabanlı sağlama toplamı hesaplayın (tüm karakterleri xoring gibi). İmzalar farklıysa, dizeler birbirinin dönüşü değildir.

Anlaşıldı, başarısız olabilir, ancak dizelerin eşleşip eşleşmediğini söylemek çok hızlıdır ve eşleşirse yine de kontrol etmek için dize birleştirme gibi başka bir algoritma kullanabilirsiniz.


1

Dayalı bir diğer Yakut çözümü cevap:

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

1

PHP fonksiyonlarını strlenve strposfonksiyonlarını kullanarak yazmak çok kolaydır :

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

strposDahili olarak ne kullandığını bilmiyorum , ancak KMP kullanıyorsa, bu zaman içinde doğrusal olacaktır.


1

Dizelerden birini ters çevirin. Her ikisinin de FFT'sini alın (basit tamsayı dizileri olarak ele alın). Sonuçları birlikte akıllıca çarpın. Ters FFT kullanarak geri dönüşümü. Eğer dizeler birbirinin rotasyonu ise sonuç tek bir zirveye sahip olacaktır - zirvenin pozisyonu birbirlerine göre ne kadar döndürüldüklerini gösterir.


0

Neden böyle bir şey olmasın?


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

Tabii ki, kendi IndexOf () fonksiyonunuzu yazabilirsiniz; .NET'in saf bir yol mu yoksa daha hızlı bir yol mu kullandığından emin değilim.

naif:


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;
}

Daha hızlı:


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;
}

Düzenleme: Bazı off-by-one sorunları olabilir; kontrol etmek istemiyorum. ;)


0

Bunu Perl'de yapardım :

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

Üyelik string1ile string2ve kullanımı KMP algoritması olup olmadığını kontrol etmek için string2yeni kurulan dizede bulunur. Çünkü KMP'nin zaman karmaşıklığı bundan daha azdır substr.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.