インタビューの質問:1つの文字列が他の文字列の回転であるかどうかを確認します[終了]


235

私の友人は本日、ソフトウェア開発者の立場についてのインタビューで次の質問をされました:

2つの文字列を考えるs1s2、どのようにかどうかをチェックしますs1、回転のバージョンs2

例:

場合はs1 = "stackoverflow"、その後、次はその回転バージョンの一部です:

"tackoverflows"
"ackoverflowst"
"overflowstack"

ここで、as "stackoverflwo"はローテーションバージョンではありません

彼が出した答えは:

s2サブストリングである最長の接頭辞を取得して見つけますs1。これにより、回転のポイントが得られます。そのポイントを見つけたら、そのポイントで中断s2してとを取得s2as2b、次にconcatenate(s2a,s2b) == s1

それは私と私の友人にとって良い解決策のように見えます。しかし、インタビュアーはそうではないと考えました。彼はもっと簡単な解決策を求めました。これをどのように行うのか教えてくださいJava/C/C++

前もって感謝します。


4
concatenate(s2a、s2b)== s1かどうかを確認する必要はありません。これは、s2aがs1の先頭に等しいことがわかっているためです。s2b == s1のサブストリングがrotation_pointから末尾までかどうかを確認するだけです。
Jason Hall

33
この質問とトップの回答はどのようにして多くの賛成票を獲得しましたか?
David Johnstone、

9
@David:面白いから。
Cam

6
非常に興味深く、エレガントでシンプルな答えです。
グル

7
@David:それはここで前に尋ねられない質問であり、 もが理解する質問であるため(質問/回答を理解していない場合、通常はそれを賛成しないでしょう。かなり単純な質問の方が対象範囲が広いです)これはJavaとCの両方でタグ付けされているためです。カウントされます:)
BalusC '19

回答:


687

まず、同じ長さであることを確認s1s2てください。次にs2、とs1連結された部分文字列であるかどうかを確認します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の場合:

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

49
私はその優雅さが好きですが、誤検知がないことを確認するためにしばらく考える必要がありました。(私はそこにいる思いません。)
ジョン・スキート2010年

6
(s1+s1).contains(s2)Java でも使用できます。
polygenelubricants 2010年

4
とにかく、私はこれをインタビューの質問として少し反対します。「あはは!」コンポーネントだと思います。ほとんどのプログラマー(私も含まれます)はブルートフォースを使用しますが、それはとにかく不合理ではありません。
ダニエルダラナス

5
@Jonに集中しs1+s1ます。明らかに、サイズs1.lengthを持つそのすべてのサブストリングはs1、構造上、のローテーションです。したがって、のs1.length部分文字列であるサイズの文字列はs1+s1、のローテーションである必要がありますs1
ダニエルC.ソブラル2010

6
@unicornaddict-このソリューションの優れている点は、一度指摘すればそれが明らかであることです。私はそれについて考えていなかったことを嫌いです!
James B

101

確かに、より良い答えは、「まあ、私はstackoverflowコミュニティに質問し、おそらく5分以内に少なくとも4つの本当に良い答えがあるだろう」でしょう。脳はすべて良いですが、私は解決策を得るために他の人と協力する方法を知っている人を高く評価します。


14
真っ赤な頬に+1。私の日を作った:-)
プラチナアズール

5
同意しない場合は、この質問にリンクできます。
Cam

51
面接中に携帯電話をむちで打つことは失礼と見なされる可能性があり、結局彼らはジョン・スキートを雇うことになるでしょう。
tstenner 2010

2
それは実際、おそらく私が言ったこととまったく同じだろう
クリス・ダトロー2010年

6
ジョン・スキートを買う余裕はないと思います。
SolutionYogi

49

別のpythonの例(答えに基づく):

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

1
興味深いことに、私s2s1あまりにも重複しているのではないかと考えました...その後、関係が対称的であることに気付きました。
Matthieu M.

1
文字列が長くなる可能性がある場合は、Boyer-Mooreを使用してO(n)実行時間を取得するPythonバージョンを次に示します。def isrotation(s1、s2):return len(s1)== len(s2)and re.compile(re .escape(s1))。search(2 * s2)はNoneではありません
Duncan

2
@ダンカン:in演算子はO(n)アルゴリズムを使用しませんか?
ケンブルーム

1
@Duncan:Python文字列メソッドは、最適化されたBoyer-Moore-Horspoolを使用します。Javaにも同様の最適化があるのでしょうか。
Thomas Ahle、2011年

1
@Thomas指摘してくれてありがとう。私は正規表現だけがボイヤー・ムーアを使用していると思っていましたが、私は間違っていました。Python 2.4以前の場合、私の答えは正しかったが、Python 2.5 s1 in s2が最適化されているため。アルゴリズムの説明については、effbot.org / zone / stringlib.htmを参照してください。グーグルはJavaが高速の文字列検索(例えばjohannburkard.de/software/stringsearchを参照)を持っていないことを示しているようですが、彼らがそれを変更した場合、それが何かを壊すとは思えません。
ダンカン

32

他の人が2次の最悪の場合の時間の複雑さのソリューションを提出したので、線形のソリューションを追加します(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;
}

実例


5
ideone.comの+1-非常に興味深いようです。
Martin Vseticka 2010

25

編集:あなたがそれを見つければ、受け入れられた答えはこれよりも明らかにエレガントで効率的です。この答えは、元の文字列を2倍にすることを考えていなかった場合の対処法として残しました。


私はそれを総当たりするだろう。最初に長さを確認してから、考えられるすべての回転オフセットを試してください。どれもうまくいかない場合はfalseを返します-うまくいかない場合はすぐにtrueを返します。

特に連結する必要はありません-ポインター(C)またはインデックス(Java)を使用して、各文字列に1つずつ両方をたどります。 。文字列の各ポイントで文字が等しいかどうかを確認します。最初の文字列の終わりに到達したら、完了です。

それはおそらく連結するのと同じくらい簡単でしょう-少なくともJavaではおそらくそれほど効率的ではありません。


8
+1-最も効率的なソリューションの3倍以上で実行されるエレガントなソリューションは必要ありません。これはCです...マイクロ最適化は厳密ではありません
スティーブンC

8
インタビュアー:ロッタは話しますが、この男はコーディングできないと思います。
ハンフリーボガート、

8
@Beau:誰かがそれを考えたいと思っているなら、彼らは私にコードを尋ねることを歓迎します。誰かが私に「どうやってやるの?」
Jon Skeet

3
@ジョン-私はボーのコメントを冗談だと読んだ
oxbow_lakes 2010年

37
@ジョンそれは冗談でした!インタビュアーはジョンスキートにインタビューしません。ジョンスキートが彼にインタビューします。
ハンフリーボガート

17

楽しみのために正規表現を使用しているものは次のとおりです。

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

どちらの文字列にも含まれないことが保証されている特殊な区切り文字を使用できる場合は、少し単純にすることができます。

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

代わりに、有限繰り返しで後読みを使用することもできます。

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

6
正規表現マスターであることの+1。
Chris Thornton

-1「regex」と「fun」という単語を同じステートメントに入れるため、「fun」を「not」で変更せずに(冗談ですが、私は反対票を投じませんでした)
Binary Worrier

-3正規表現が楽しくないことを意味します。
manlycode

この正規表現「(。*)(。*)= \\ 2 \\ 1」がどのように機能するかを任意のボディplzが説明できます!
mawia 2010年

10

おっと、おっと...なぜ誰もがそんなにO(n^2)答えにわくわくするのですか?私たちはここでもっと上手くできると確信しています。上記の答えには、ループ内のO(n)操作O(n)(substring / indexOf呼び出し)が含まれています。より効率的な検索アルゴリズムを使用しても、Boyer-Mooreまたはと言ってもKMP、最悪のケースはまだO(n^2)重複しています。

O(n)無作為化答えは簡単です。O(1)スライディングウィンドウをサポートする(Rabinフィンガープリントのような)ハッシュを取得します。ハッシュ文字列1、次にハッシュ文字列2、ハッシュ1のウィンドウを文字列の周りに移動し、ハッシュ関数が衝突するかどうかを確認します。

最悪のケースが「DNAの2つのストランドをスキャンする」ようなものだと想像すると、衝突の確率が高くなり、これはおそらくO(n^(1+e))何か(ここで推測)に悪化します。

最後に、O(nlogn)非常に大きな定数が外部にある確定的な解決策があります。基本的に、アイデアは2つの文字列の畳み込みを取ることです。畳み込みの最大値は回転の差になります(回転されている場合)。O(n)チェック確認します。良いことは、2つの等しい最大値がある場合、どちらも有効なソリューションであることです。2つのFFTとドット積、およびiFFTで畳み込みを行うことができますnlogn + nlogn + n + nlogn + n == O(nlogn)

ゼロを埋め込むことはできず、文字列の長さが2 ^ nであることを保証できないため、FFTは高速ではありません。それらは遅いものO(nlogn)ですが、CTアルゴリズムよりもはるかに大きな定数です。

そうは言っても、私はO(n)断固として、ここには確定的な解決策があることを100%肯定していますが、それを見つけることができるかどうかは気の毒です。


それ自体で連結された文字列(物理的にまたは仮想的にaを使用%stringsize)のKMPは、線形時間であることが保証されています。
Kragen Javier Sitaker、2010

Rabin-Karpの+1。KMPとは異なり、一定のスペースを使用し、実装が簡単です。(これは私が考えた最初の回答でもあり、数秒で「正しい」回答は見づらくなります。これはそこにあり、甘いからです。)あなたの畳み込みのアイデアは、Shorのアルゴリズムを思い出させます-部分線形があるのだろうか量子ソリューション-しかし、それは今ばかげていますね?
ダライアスベーコン

1
RKは決定論的なO(n)解を与えず、KMPは空間ではO(n)であり、望ましくない場合があります。時間のO(n)と空間のO(1)の双方向検索またはSMOAサブストリング検索を検索します。ちなみに、glibc strstrはTwo Wayを使用していますが、%lenを使用するのではなく実際に文字列を連結して使用すると、空間でO(n)に戻ります。:-)
R .. GitHub ICE HELPING ICEの停止

8

まず、2つの弦の長さが同じであることを確認します。その後、Cでは、単純なポインター反復でこれを行うことができます。


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
ああ、C。Cで実行できるのに、なぜ半分の時間でコードを作成してコード化するのですか。
ハンフリーボガート

11
+1非常によく書かれたCです。公平を期すために、質問には「c」というタグを付けています。
Nick Moore、

5
このコードでは、(strlenとstrcmpで)3回ではなくても少なくとも2回文字列をウォークしました。このチェックを省いて、ロジックをループに保持することができます。ループしているときに、1つの文字列の文字数が他の文字数と異なる場合は、ループを終了します。開始点がわかっていて、いつヌルターミネーターに到達したかがわかるので、長さがわかります。
Nasko、

12
@Beau Martinez-時々、開発時間よりも実行時間の方が重要であるため:-)
phkahler 2010年

2
@phkahler-問題は、それがかなり遅いかもしれないということです。他の言語の組み込みインデックス関数は、通常、Boyer-Moore、Rabin-Karp、Knuth-Morris-Prattなどの高速文字列検索アルゴリズムを使用します。Cですべてを再発明し、それがより高速であると仮定するだけでは、単純すぎる。
Thomas Ahle

8

ここに、O(n)その場でのalghoritmがあります。<文字列の要素に演算子を使用します。もちろん、私のものではありません。私はここからそれを取りまし(このサイトは洗練されています。過去に一度偶然見つけましたが、今はそのようなものを英語で見つけることができなかったので、私が持っているものを示します:))。

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)だけですっごくはるかに深いからCOMP-SCIの観点以外よりもO(n)の溶液:)
SyntaxT3rr0r

4
+1は、時間的に最適で、コードサイズ(バイナリとLoCの両方)がほぼ最適なソリューションです。この答えは説明があればさらに良いでしょう。
R .. GitHub ICE HELPING ICEの停止

完全に不可解。説明が必要です!
j_random_hacker '10

7

私はこれをJava次のように行う方が良いと思います:

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

Perlでは、次のようにします。

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

正規表現の代わりにインデックス関数を使用することもできます:

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

1
忘れ\Qました/\Q$string2/
Kragen Javier Sitaker 2010

3
\Qで特殊文字を引用符で囲みます$string2。これがない場合、.1文字の文字列のローテーションと見なされます。
jackrabbit 2010

6

これが最も効率的な方法であるかどうかはわかりませんが、比較的興味深い方法かもしれません。Burrows-Wheeler変換です。WP記事によると、入力のすべてのローテーションは同じ出力を生成します。圧縮などのアプリケーションでは、これは望ましくないため、元の回転が示されます(たとえば、インデックスによって示されます。記事を参照してください)。しかし、回転に依存しない単純な比較には、理想的に聞こえます。もちろん、それは必ずしも理想的に効率的ではありません!


Burrows-Wheeler変換には文字列のすべての回転の計算が含まれるため、最適とは言えません.. :-)
R .. GitHub STOP HELPING ICE

6

各文字を振幅として取り、それらに対して離散フーリエ変換を実行します。回転だけが異なる場合、周波数スペクトルは丸め誤差内と同じになります。もちろん、これは長さが2の累乗でない限り非効率で、FFTを実行できます:-)


これを興味深いコーディング演習として使用しましたが、それを評価できるかどうかはわかりません;)。
jayshao

FFTの乱用:)私からの+1
アーミル

5

まだモジュロアプローチを提供していないので、ここに1つあります。

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

出力:

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

[編集:2010-04-12]

piotrは上記の私のコードの欠陥に気づきました。文字列の最初の文字が2回以上出現するとエラーになります。たとえば、stackoverflowテストを実行するowstackoverflowと、trueであるはずのfalseが返されます。

エラーを発見してくれたpiotrに感謝します。

さて、これが修正されたコードです:

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

出力は次のとおりです。

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

ラムダアプローチは次のとおりです。

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

ラムダアプローチの出力は次のとおりです。

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

int ndx = a.IndexOf(b [0]);なので、あなたの答えは正しいとは思いません。文字列にb [0]の同じ値を持つ他の要素がない場合にのみ機能します。
piotr 2010

欠陥に気づいてくれてありがとう。今すぐ修正
Michael Buen

3

誰もC ++ソリューションを提供していないので。ここにそれ:

bool isRotation(string s1,string s2) {

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

カップルポイント:長さが一致しない場合でも、比較的コストのかかる文字列の連結を行っています。あなたはconst参照によってs2を渡すことができます。
Tony Delroy、2011年

2

Operaの単純なポインター回転トリックは機能しますが、実行時間の最悪のケースでは非常に非効率的です。多くの長い繰り返しの文字列を含む文字列を単に想像してください。

S1 = HELLOHELLOHELLO1HELLOHELLOHELLO2

S2 = HELLOHELLOHELLO2HELLOHELLOHELLO1

「不一致が見つかるまでループし、1ずつインクリメントしてもう一度試す」は、計算上は恐ろしいアプローチです。

あまり努力せずにプレーンCで連結アプローチを実行できることを証明するために、これが私の解決策です。

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

これは、オーバーヘッドのO(n)メモリ使用量を犠牲にして、実行時間に比例します。

(strstr()の実装はプラットフォーム固有ですが、特に頭の痛い場合は、常にBoyer-Mooreアルゴリズムなどのより高速な代替手段で置き換えることができます)


1
strstr()O(n + m)を持つプラットフォームを知っていますか?また、標準(または他の何か)がの線形実行時間を保証しない場合、strstr()アルゴリズム全体が線形時間の複雑さを持っていると断言することはできません。
jpalecek 2010

これが、ボイヤー・ムーアアルゴリズムに置き換えて線形時間で実行できると私が言った理由です。
RarrRarrRarr 2010

割り当ての方法にはいくつかの潜在的な問題がありますs1SelfConcat。C9x以来、Cは可変配列サイズを許可しているため(GCCではこれよりずっと長い時間が許可されています)、スタックに大きな文字列を割り当てるときに問題が発生します。Yosef Kreininがこの問題について非常に面白いブログ投稿を書い。また、あなたの解決策は、まだボイヤー・ムーアの二次時間です。あなたはKMPが欲しい。
Kragen Javier Sitaker、2010


2

私は、s2がs1と連結されたs1のサブストリングであるかどうかをチェックする答えが好きです。

その優雅さを失わない最適化を追加したかったのです。

文字列を連結する代わりに、結合ビューを使用できます(他の言語についてはわかりませんが、C ++ではBoost.Rangeがそのようなビューを提供します)。

文字列が別の文字列の部分文字列であるかどうかのチェックは、線形の平均複雑度(最悪の場合の複雑度は二次式)であるため、この最適化は速度を平均で2倍向上させるはずです。


2

純粋なJavaの回答(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

そして今、完全に異なる何かのために。

文字列が互いの回転ではないときに、いくつかの制約されたコンテキストで本当に速い答えが欲しい場合

  • 両方の文字列について、文字ベースのチェックサム(すべての文字をxorするなど)を計算します。署名が異なる場合、文字列は相互のローテーションではありません。

同意すると失敗する可能性がありますが、文字列が一致しない場合は非常に高速で、一致する場合は、文字列連結などの別のアルゴリズムを使用して確認できます。


1

基づいて、他のRubyのソリューションの答え:

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

1

strlenstrpos関数を使用してPHPで記述するのは非常に簡単です。

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

strpos内部で何が使用されているかはわかりませんが、KMPを使用している場合、これは時間的に線形になります。


1

文字列の1つを逆にします。両方のFFTを取ります(それらを整数の単純なシーケンスとして扱います)。結果をポイントごとに乗算します。逆FFTを使用して変換します。文字列が互いの回転である場合、結果は単一のピークになります-ピークの位置は、それらが互いに対してどれだけ回転しているかによって示されます。


0

なぜこのようなものではないのですか?


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

もちろん、独自のIndexOf()関数を作成することもできます。.NETが単純な方法と高速な方法のどちらを使用しているかはわかりません。

素朴:


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

もっと早く:


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

編集:いくつかの問題があります。確認したくない。;)


0

私はこれを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

に参加string1string2KMPアルゴリズムを使用してstring2、新しく形成された文字列にが存在するかどうかを確認します。KMPの時間の複雑さはよりも少ないからですsubstr

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.