Pertanyaan wawancara: Periksa apakah satu string merupakan rotasi dari string lain [tertutup]

235

Seorang teman saya ditanya pertanyaan berikut hari ini di wawancara untuk posisi pengembang perangkat lunak:

Mengingat dua string yang s1dan s2bagaimana Anda akan memeriksa apakah s1merupakan diputar versi s2?

Contoh:

Jika s1 = "stackoverflow"kemudian berikut ini adalah beberapa versi rotasinya:

"tackoverflows"
"ackoverflowst"
"overflowstack"

dimana "stackoverflwo"adalah tidak versi yang diputar.

Jawaban yang dia berikan adalah:

Ambil s2dan temukan awalan terpanjang yang merupakan sub string s1, yang akan memberi Anda titik rotasi. Setelah Anda menemukan titik itu, istirahat s2pada titik itu untuk mendapatkan s2adan s2b, lalu periksa apakahconcatenate(s2a,s2b) == s1

Sepertinya solusi yang baik untuk saya dan teman saya. Tetapi pewawancara berpikir sebaliknya. Dia meminta solusi yang lebih sederhana. Tolong bantu saya dengan mengatakan bagaimana Anda melakukan ini Java/C/C++?

Terima kasih sebelumnya.

Webdev
sumber
4
Anda tidak perlu memeriksa apakah concatenate (s2a, s2b) == s1, karena Anda tahu s2a sama dengan awal s1. Anda bisa memeriksa apakah s2b == substring dari s1 dari rotasi_point ke ujung.
Jason Hall
33
Bagaimana pertanyaan dan jawaban teratas ini mendapatkan begitu banyak upvotes !?
David Johnstone
9
@ David: Karena itu menarik.
Cam
6
Saya akan mengatakan, jawaban yang sangat menarik dan elegan, sederhana.
Guru
7
@ David: karena ini adalah pertanyaan yang tidak ditanyakan sebelumnya di sini dan juga yang dipahami semua orang (jika seseorang tidak memahami pertanyaan / jawaban, seseorang biasanya pasti tidak akan menjawabnya; pertanyaan yang cukup sederhana memiliki audiens yang lebih luas) dan juga karena ini telah ditandai dengan Java dan C. Ini diperhitungkan :)
BalusC

Jawaban:

687

Pertama pastikan s1dan s2memiliki panjang yang sama. Kemudian periksa untuk melihat apakah s2substring dari s1digabungkan dengan 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

Di Jawa:

boolean isRotation(String s1,String s2) {
    return (s1.length() == s2.length()) && ((s1+s1).indexOf(s2) != -1);
}
codaddict
sumber
49
Saya suka keanggunannya, tetapi saya harus berpikir sebentar untuk memeriksa tidak ada positif palsu. (Saya tidak berpikir ada.)
Jon Skeet
6
Anda juga bisa menggunakannya (s1+s1).contains(s2)di Jawa.
polygenelubricants
4
Pokoknya saya akan sedikit keberatan dengan ini sebagai pertanyaan wawancara. Ini memiliki "aha!" komponen, saya pikir. Sebagian besar programmer (termasuk saya) hanya akan menggunakan kekerasan, yang tidak masuk akal pula, dan itu mungkin terasa seperti tidak "cukup pintar" untuk pewawancara.
Daniel Daranas
5
@Jon Berkonsentrasi pada s1+s1. Jelas, semua substringnya dengan ukuran s1.lengthadalah rotasi s1, oleh konstruksi. Oleh karena itu, setiap string ukuran s1.lengthyang merupakan substring s1+s1harus berupa rotasi s1.
Daniel C. Sobral
6
@ unicornaddict - apa yang hebat tentang solusi ini adalah begitu jelas setelah Anda menunjukkannya, saya benci diri saya sendiri karena tidak memikirkannya!
James B
101

Tentunya jawaban yang lebih baik adalah, "Yah, saya akan bertanya kepada komunitas stackoverflow dan mungkin akan memiliki setidaknya 4 jawaban yang benar-benar bagus dalam 5 menit". Otak baik dan semuanya, tetapi saya akan memberi nilai lebih tinggi pada seseorang yang tahu bagaimana bekerja dengan orang lain untuk mendapatkan solusi.

Chris Knight
sumber
14
+1 untuk pipi tipis. Jadikan hari saya :-)
Platinum Azure
5
Jika mereka tidak setuju, Anda dapat menautkannya ke pertanyaan ini.
Kamera
51
Mengeluarkan ponsel Anda selama wawancara mungkin dianggap kasar dan pada akhirnya mereka akhirnya akan mempekerjakan Jon Skeet.
tstenner
2
Thats sebenarnya mungkin persis apa yang akan saya katakan
Chris Dutrow
6
Saya tidak berpikir mereka akan mampu membayar Jon Skeet.
SolutionYogi
49

Contoh python lain (berdasarkan jawaban THE):

def isrotation(s1,s2):
     return len(s1)==len(s2) and s1 in 2*s2
Federico A. Ramponi
sumber
1
Menariknya saya memikirkan duplikat s2daripada s1terlalu ... kemudian menyadari bahwa hubungannya memang simetris.
Matthieu M.
1
Jika string bisa panjang, inilah versi Python yang menggunakan Boyer-Moore untuk mendapatkan O (n) waktu berjalan: def isrotation (s1, s2): return len (s1) == len (s2) dan re.compile (re .escape (s1)). search (2 * s2) tidak ada
Duncan
2
@Uncunc: apakah inoperator tidak menggunakan algoritma O (n)?
Ken Bloom
1
@Duncan: Metode string python menggunakan Boyer-Moore-Horspool yang dioptimalkan. Saya ingin tahu apakah Java memiliki optimasi yang serupa.
Thomas Ahle
1
@ Thomas terima kasih telah menunjukkan itu. Saya berpikir bahwa hanya ekspresi reguler yang menggunakan Boyer-Moore tetapi saya melihat saya salah. Untuk Python 2.4 dan sebelumnya jawaban saya benar tetapi karena Python 2.5 s1 in s2dioptimalkan. Lihat effbot.org/zone/stringlib.htm untuk deskripsi algoritme. Google tampaknya menunjukkan bahwa Java tidak memiliki pencarian string cepat (lihat johannburkard.de/software/stringsearch misalnya) meskipun saya ragu itu akan merusak apa pun jika mereka mengubahnya.
Duncan
32

Karena orang lain telah mengirimkan solusi kompleksitas waktu terburuk kuadratik, saya akan menambahkan yang linear (berdasarkan Algoritma 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;
}

contoh kerja

jpalecek
sumber
5
+1 untuk ideone.com - tampilannya sangat menarik!
Martin Vseticka
25

EDIT: Jawaban yang diterima jelas lebih elegan dan efisien daripada ini, jika Anda menemukannya. Saya meninggalkan jawaban ini sebagai apa yang akan saya lakukan jika saya tidak berpikir untuk menggandakan string aslinya.


Aku hanya akan memaksanya dengan kasar. Periksa panjangnya terlebih dahulu, dan kemudian coba setiap pergantian rotasi yang dimungkinkan. Jika tidak ada yang berhasil, kembalikan salah - jika ada yang benar, kembalikan benar segera.

Tidak ada kebutuhan khusus untuk menggabungkan - cukup gunakan pointer (C) atau indeks (Jawa) dan berjalan bersama, satu di setiap string - mulai dari awal satu string dan rotasi kandidat saat ini diimbangi pada string kedua, dan membungkus jika perlu . Periksa persamaan karakter di setiap titik dalam string. Jika Anda sampai ke akhir string pertama, Anda sudah selesai.

Mungkin akan lebih mudah untuk digabungkan - meskipun mungkin kurang efisien, setidaknya di Jawa.

Jon Skeet
sumber
8
+1 - kita tidak perlu solusi elegan yang berjalan dalam 3+ kali solusi paling efisien. Ini adalah C ... optimasi mikro adalah de riguer .
Stephen C
8
Pewawancara: Lotta bicara, tapi saya yakin orang ini tidak bisa kode.
Humphrey Bogart
8
@Beau: Jika ada yang ingin berpikir seperti itu, mereka dipersilakan untuk meminta saya kode. Jika seseorang bertanya kepada saya "bagaimana saya akan melakukan sesuatu" Saya biasanya menggambarkan algoritma daripada melompat ke kode.
Jon Skeet
3
@Jon - Saya membaca komentar Beau sebagai lelucon
oxbow_lakes
37
@ Jon Itu hanya lelucon! Pewawancara tidak mewawancarai Jon Skeet, Jon Skeet mewawancarainya.
Humphrey Bogart
17

Inilah satu menggunakan regex hanya untuk bersenang-senang:

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

Anda dapat membuatnya sedikit lebih sederhana jika Anda dapat menggunakan karakter pembatas khusus yang dijamin tidak berada di kedua string.

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

Anda juga dapat menggunakan lookbehind dengan pengulangan terbatas:

boolean isRotation(String s1, String s2) {
   return (s1 + s2).matches(
      String.format("(.*)(.*)(?<=^.{%d})\\2\\1", s1.length())
   );
}
polygenelubricants
sumber
6
+1 untuk menjadi master regex.
Chris Thornton
-1 Untuk menempatkan kata "regex" dan "kesenangan" dalam pernyataan yang sama, tanpa memodifikasi "kesenangan" dengan "tidak" (hanya bercanda, saya tidak memilih)
Binary Worrier
-3 untuk menyatakan bahwa regex tidak menyenangkan.
manlycode
bisakah ada badan yang menjelaskan bagaimana regex ini "(. *) (. *) = \\ 2 \\ 1" bekerja!
mawia
10

Whoa, whoa ... mengapa semua orang sangat senang dengan O(n^2)jawaban? Saya yakin kita bisa melakukan yang lebih baik di sini. THE THE jawaban di atas termasuk O(n)operasi dalam satu O(n)lingkaran (panggilan substring / indexOf). Bahkan dengan algoritma pencarian yang lebih efisien; katakan Boyer-Mooreatau KMP, kasus terburuk masih O(n^2)dengan duplikat.

Sebuah O(n)jawaban yang acak adalah mudah; ambil hash (seperti sidik jari Rabin) yang mendukung O(1)jendela geser; string hash 1, kemudian string hash 2, dan lanjutkan untuk memindahkan jendela hash 1 di sekitar string dan melihat apakah fungsi hash bertabrakan.

Jika kita membayangkan kasus terburuk adalah sesuatu seperti "memindai dua untai DNA", maka kemungkinan tabrakan meningkat, dan ini mungkin merosot menjadi sesuatu seperti O(n^(1+e))atau sesuatu (hanya menebak di sini).

Akhirnya, ada O(nlogn)solusi deterministik yang memiliki konstanta yang sangat besar di luar. Pada dasarnya, idenya adalah mengambil konvolusi dari dua string. Nilai maksimal konvolusi adalah perbedaan rotasi (jika diputar); sebuah O(n)cek mengonfirmasi. Yang menyenangkan adalah jika ada dua nilai maks yang sama, maka keduanya merupakan solusi yang valid. Anda dapat melakukan konvolusi dengan dua produk FFT dan dot, dan iFFT, jadi nlogn + nlogn + n + nlogn + n == O(nlogn).

Karena Anda tidak dapat membuat angka nol, dan Anda tidak dapat menjamin bahwa string memiliki panjang 2 ^ n, FFT tidak akan menjadi yang cepat; mereka akan menjadi yang lambat, masih O(nlogn)tetapi konstanta yang jauh lebih besar daripada algoritma CT.

Semua yang dikatakan, saya benar-benar, 100% positif bahwa ada O(n)solusi deterministik di sini, tetapi terkutuk jika saya dapat menemukannya.

user295691
sumber
KMP pada string concatenated-with-itself (baik secara fisik atau hampir dengan a %stringsize) dijamin menjadi waktu linier.
Kragen Javier Sitaker
+1 untuk Rabin-Karp. Tidak seperti KMP, ini menggunakan ruang konstan, dan lebih mudah untuk diterapkan. (Itu juga jawaban pertama yang saya pikirkan, dalam hitungan detik, membuatnya sulit untuk melihat jawaban yang 'benar', karena yang ini ada di sana dan itu manis.) Ide konvolusi Anda mengingatkan saya pada algoritma Shor - Saya ingin tahu apakah ada sublinear solusi kuantum - tapi itu konyol sekarang, kan?
Darius Bacon
1
RK tidak memberikan solusi deterministik O (n), dan KMP adalah O (n) dalam ruang yang mungkin tidak diinginkan. Cari pencarian Substring Dua Arah atau SMOA yang keduanya O (n) dalam waktu dan O (1) di ruang angkasa. By the way, glibc strstr menggunakan Two Way, tetapi jika Anda benar-benar menggabungkan string untuk menggunakannya sebagai kebalikan dari menggunakan% len Anda kembali ke O (n) di ruang angkasa. :-)
R .. GitHub BERHENTI MEMBANTU ICE
8

Tinju, pastikan 2 senar memiliki panjang yang sama. Kemudian di C, Anda bisa melakukan ini dengan iterasi pointer sederhana.


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);
}
Opera
sumber
19
Ah, C. Mengapa melakukan sesuatu di separuh waktu dan kode ketika Anda bisa melakukannya di C!
Humphrey Bogart
11
+1 Ini ditulis dengan sangat baik C. Dan agar adil, pertanyaannya ditandai 'c'.
Nick Moore
5
Dalam kode ini Anda telah menjalankan string setidaknya 2 jika tidak 3 kali (dalam strlen dan strcmp). Anda dapat menyimpan sendiri cek ini dan menyimpan logika itu dalam loop Anda. Saat Anda melakukan perulangan, jika satu jumlah karakter string berbeda dari yang lain, keluar dari perulangan. Anda akan mengetahui panjangnya, karena Anda tahu awal dan Anda tahu kapan Anda telah memukul terminator nol.
Nasko
12
@Beau Martinez - karena terkadang waktu eksekusi lebih penting daripada waktu pengembangan :-)
phkahler
2
@phkahler - Masalahnya mungkin lebih lambat. Fungsi indeks bawaan dalam bahasa lain biasanya menggunakan algoritma pencarian string cepat seperti Boyer-Moore, Rabin-Karp atau Knuth-Morris-Pratt. Itu terlalu naif hanya menemukan kembali semuanya dalam C, dan menganggapnya lebih cepat.
Thomas Ahle
8

Di sini ada O(n)dan di tempat alghoritm. Ini menggunakan <operator untuk elemen string. Tentu saja itu bukan milikku. Saya mengambilnya dari sini (Situs ini dalam bahasa Polandia. Saya menemukannya sekali di masa lalu dan saya tidak dapat menemukan sesuatu seperti itu sekarang dalam bahasa Inggris, jadi saya menunjukkan apa yang saya miliki :)).

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;
}
Maciej Hehl
sumber
+1 ... O (n) adalah sooooo jauh lebih mendalam dari sudut pandang comp-sci daripada solusi non O (n) :)
SyntaxT3rr0r
4
+1 untuk solusi yang optimal dalam waktu dan hampir-optimal dalam ukuran kode (baik biner dan LoC). Jawaban ini akan lebih baik dengan penjelasan.
R .. GitHub STOP BANTUAN ICE
Benar-benar membingungkan. Kami butuh penjelasan!
j_random_hacker
7

Saya kira lebih baik melakukan ini di Java:

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

Dalam Perl saya akan melakukan:

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

atau bahkan lebih baik menggunakan fungsi indeks daripada regex:

sub isRotation {
 my($string1,$string2) = @_;
 return length($string1) == length($string2) && index($string2,$string1.$string1) != -1;
}
Zacky112
sumber
1
Anda lupa \Qdi /\Q$string2/.
Kragen Javier Sitaker
3
\Qmengutip setiap karakter khusus di $string2. Tanpanya, .akan dianggap sebagai rotasi dari string 1 karakter.
jackrabbit
6

Tidak yakin apakah ini adalah metode yang paling efisien, tetapi mungkin relatif menarik : transformasi Burrows-Wheeler . Menurut artikel WP, semua rotasi input menghasilkan output yang sama. Untuk aplikasi seperti kompresi ini tidak diinginkan, jadi rotasi aslinya ditunjukkan (misalnya dengan indeks; lihat artikel). Tetapi untuk perbandingan rotasi-independen sederhana, ini terdengar ideal. Tentu saja, itu belum tentu efisien secara ideal!

Edmund
sumber
Karena transformasi Burrows-Wheeler melibatkan komputasi semua rotasi string, itu pasti tidak akan menjadi optimal .. :-)
R .. GitHub BERHENTI MEMBANTU ICE
6

Ambil setiap karakter sebagai amplitudo dan lakukan transformasi Fourier diskrit pada mereka. Jika mereka berbeda hanya dengan rotasi, spektrum frekuensi akan sama dengan kesalahan pembulatan. Tentu saja ini tidak efisien kecuali panjangnya adalah kekuatan 2 sehingga Anda dapat melakukan FFT :-)

phkahler
sumber
Kami telah menggunakan ini sebagai latihan pengkodean yang menarik, saya tidak yakin kami dapat mengevaluasi itu;).
jayshao
FFT disalahgunakan :) +1 dari saya
Aamir
5

Belum ada yang menawarkan pendekatan modulo, jadi inilah salah satu:

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

Keluaran:

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

[EDIT: 2010-04-12]

piotr memperhatikan cacat pada kode saya di atas. Kesalahan saat karakter pertama dalam string muncul dua kali atau lebih. Sebagai contoh,stackoverflow diuji terhadap owstackoverflowmenghasilkan false, padahal seharusnya benar.

Terima kasih piotr karena menemukan kesalahan.

Sekarang, inilah kode yang diperbaiki:

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

Inilah hasilnya:

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

Inilah pendekatan 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

Inilah output pendekatan 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
Michael Buen
sumber
Saya tidak berpikir jawaban Anda benar karena int ndx = a.IndexOf (b [0]); hanya akan bekerja jika tidak ada elemen lain dengan nilai yang sama dengan b [0] dalam string.
piotr
terima kasih telah memperhatikan kekurangannya. dikoreksi sekarang
Michael Buen
3

Karena tidak ada yang memberikan solusi C ++. ini dia:

bool isRotation(string s1,string s2) {

  string temp = s1;
  temp += s1;
  return (s1.length() == s2.length()) && (temp.find(s2) != string::npos);
}
user324138
sumber
Poin pasangan: Anda melakukan penggabungan string yang relatif mahal bahkan jika panjangnya tidak cocok; Anda bisa melewati s2 dengan referensi const.
Tony Delroy
2

Trik rotasi pointer sederhana Opera berfungsi, tetapi sangat tidak efisien dalam kasus terburuk dalam menjalankan waktu. Cukup bayangkan sebuah string dengan banyak karakter berulang yang panjang, yaitu:

S1 = HELLOHELLOHELLO1HELLOHELLOHELLO2

S2 = HELLOHELLOHELLO2HELLOHELLOHELLO1

"Lingkaran sampai ada ketidaksesuaian, lalu bertambah satu dan coba lagi" adalah pendekatan yang mengerikan, secara komputasi.

Untuk membuktikan bahwa Anda dapat melakukan pendekatan penyatuan di dataran C tanpa terlalu banyak usaha, berikut adalah solusi saya:

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

Ini linier dalam menjalankan waktu, dengan mengorbankan penggunaan memori O (n) dalam overhead.

(Perhatikan bahwa implementasi strstr () adalah platform-spesifik, tetapi jika mati otak, selalu dapat diganti dengan alternatif yang lebih cepat seperti algoritma Boyer-Moore)

RarrRarrRarr
sumber
1
Apakah Anda tahu ada platform yang ada strstr()di O (n + m)? Juga, jika standar (atau apa pun) tidak menjamin Anda waktu berjalan linier strstr(), Anda tidak dapat menyatakan bahwa keseluruhan algoritma memiliki waktu linear yang linier.
jpalecek
Itulah sebabnya saya mengatakan bahwa itu dapat digantikan oleh algoritma Boyer-Moore, membuatnya berjalan dalam waktu linier.
RarrRarrRarr
Ada beberapa masalah potensial dengan metode pengalokasian Anda s1SelfConcat: hanya sejak C9x C memungkinkan ukuran array variabel (meskipun GCC telah memperbolehkannya lebih lama), dan Anda akan mengalami kesulitan mengalokasikan string besar pada stack. Yosef Kreinin menulis posting blog yang sangat lucu tentang masalah ini. Juga, solusi Anda masih kuadratik dengan Boyer-Moore; Anda menginginkan KMP.
Kragen Javier Sitaker
2

C #:

s1 == null && s2 == null || s1.Length == s2.Length && (s1 + s1).Contains(s2)
Anthony Faull
sumber
2

Saya suka jawaban yang memeriksa apakah s2 adalah substring dari s1 yang disatukan dengan s1.

Saya ingin menambahkan pengoptimalan yang tidak kehilangan keanggunannya.

Alih-alih menyatukan string, Anda dapat menggunakan tampilan bergabung (saya tidak tahu bahasa lain, tetapi untuk C ++ Boost.Range memberikan pandangan seperti itu).

Sebagai cek jika string adalah substring dari yang lain memiliki kompleksitas rata-rata linier (Kompleksitas terburuk adalah kuadrat), optimasi ini harus meningkatkan kecepatan dengan faktor 2 rata-rata.

Vicente Botet Escriba
sumber
2

Jawaban Java murni (tidak dapat memeriksa)

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;
}
Pembawa cincin
sumber
2

Dan sekarang untuk sesuatu yang sama sekali berbeda.

Jika Anda menginginkan jawaban yang sangat cepat dalam konteks terbatas ketika string tidak dirotasi satu sama lain

  • hitung beberapa checksum berbasis karakter (seperti xoring semua karakter) pada kedua string. Jika tanda tangan berbeda string bukan rotasi satu sama lain.

Setuju, itu bisa gagal, tetapi sangat cepat untuk mengatakan jika string tidak cocok dan jika mereka cocok, Anda masih dapat menggunakan algoritma lain seperti penggabungan string untuk memeriksa.

Kriss
sumber
1

Solusi Ruby lain berdasarkan pada jawaban:

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

Sangat mudah untuk menulis dalam PHP menggunakan strlendan strposfungsi:

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

Saya tidak tahu apa yang strposdigunakan secara internal, tetapi jika menggunakan KMP ini akan linear dalam waktu.

pengguna325894
sumber
1

Balikkan salah satu senarnya. Ambil FFT keduanya (memperlakukan mereka sebagai urutan sederhana bilangan bulat). Lipat gandakan hasilnya bersamaan. Transformasikan kembali menggunakan FFT terbalik. Hasilnya akan memiliki puncak tunggal jika string adalah rotasi satu sama lain - posisi puncak akan menunjukkan seberapa besar mereka diputar sehubungan satu sama lain.

brewbuck
sumber
0

Kenapa tidak seperti ini?


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

Tentu saja, Anda dapat menulis fungsi IndexOf () Anda sendiri; Saya tidak yakin apakah .NET menggunakan cara yang naif atau lebih cepat.

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

Lebih cepat:


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

Sunting: Saya mungkin memiliki beberapa masalah satu-persatu; tidak ingin memeriksa. ;)

hehewaffles
sumber
0

Saya akan melakukan ini di Perl :

sub isRotation { 
     return length $_[0] == length $_[1] and index($_[1],$_[0],$_[0]) != -1; 
}
gameover
sumber
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;
}
dikelola
sumber
0

Bergabunglah string1dengan string2dan gunakan algoritma KMP untuk memeriksa apakah string2ada dalam string yang baru dibentuk. Karena kompleksitas waktu KMP lebih rendah daripada substr.

codaddict
sumber