面试问题:检查一个字符串是否是另一字符串的旋转[关闭]


235

我的一个朋友今天在面试中被问到以下问题,询问软件开发人员的职位:

给定两个字符串s1s2您将如何检查是否s1为的旋转版本s2

例:

如果是,s1 = "stackoverflow"那么以下是其一些轮换版本:

"tackoverflows"
"ackoverflowst"
"overflowstack"

其中,作为"stackoverflwo"旋转的版本。

他给出的答案是:

s2,发现为子串最长前缀s1,这将使你的旋转点。找到该点后,s2在该点断开以获取s2as2b,然后检查是否concatenate(s2a,s2b) == s1

对于我和我的朋友来说,这似乎是一个很好的解决方案。但是面试官却不这么认为。他要求一个更简单的解决方案。请告诉我您将如何做来帮助我Java/C/C++

提前致谢。


4
您不必检查是否串联(s2a,s2b)== s1,因为您知道s2a等于s1的开头。您可以仅检查s1的s2b ==子串从rotation_point到结尾。
杰森·霍尔

33
这个问题和最重要的答案是如何获得这么多好评的?!
大卫·约翰斯通

9
@David:因为它很有趣。
凸轮

6
我会说,这很有趣,而且是一个优雅,简单的答案。
大师

7
@David:因为这是一个之前从未问过的问题,也是每个人都 理解的问题(如果一个人不理解该问题/答案,通常肯定会否决它;一个很简单的问题会引起更多的读者),并且因为它同时被Java和C标记。它很重要:)
BalusC 2010年

Answers:


687

首先确保s1s2的长度相同。然后检查是否s2是一个s1s1以下内容串联的子字符串:

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
我喜欢它的优雅,但是我不得不考虑一会儿,以确认没有任何误报。(我认为没有。)
乔恩·斯基特

6
您也可以(s1+s1).contains(s2)在Java中使用。
polygenelubricants 2010年

4
无论如何,作为面试问题我会对此有所反对。它有一个“啊哈!” 我认为。大多数程序员(包括我在内)都只会使用蛮力,无论如何这都不是不合理的,并且对于面试官来说,这似乎还不够“聪明”。
丹尼尔·达拉纳斯

5
@Jon专注于s1+s1。显然,通过构造,其所有带有大小的子字符串s1.length都是的旋转s1。因此,任何大小s1.length为substring的字符串都s1+s1必须是的旋转s1
Daniel C. Sobral

6
@unicornaddict-该解决方案的优点是,一旦您指出它,它是如此明显,我讨厌自己不考虑它!
詹姆斯·B

101

当然,更好的答案是:“好吧,我想问一下stackoverflow社区,可能会在5分钟内至少得到4个非常好的答案”。所有人都是聪明人,但我会给那些知道如何与他人合作以寻求解决方案的人更高的价值。


14
+1为纯粹的脸颊。成就了我的一天:-)
Platinum Azure

5
如果他们不同意,则可以将其链接到此问题。
凸轮

51
在面试中窃取您的手机可能被认为是不礼貌的,最终他们最终雇用了乔恩·斯凯特(Jon Skeet)。
tstenner'4

2
那实际上可能正是我会说的
克里斯·杜特罗

6
我认为他们买不起乔恩·斯基特(Jon Skeet)。
SolutionYogi 2010年

49

另一个python示例(基于答案):

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

1
有趣的是,我想到重复,s2而不是重复s1...然后意识到该关系无论如何都是对称的。
Matthieu M.

1
如果字符串可能很长,这是一个使用Boyer-Moore获得O(n)运行时间的Python版本:def isrotation(s1,s2):返回len(s1)== len(s2)并重新编译(re .escape(s1))。search(2 * s2)不是None
Duncan 2010年

2
@Duncan:in运算符是否不使用O(n)算法?
肯·布鲁姆

1
@Duncan:python字符串方法使用优化的Boyer-Moore-Horspool。我想知道Java是否有类似的优化。
Thomas Ahle

1
@Thomas感谢您指出这一点。我以为只有正则表达式使用了Boyer-Moore,但是我发现我错了。对于Python 2.4和更早版本,我的回答是正确的,但是由于s1 in s2优化了Python 2.5 。有关算法的说明,请参阅effbot.org/zone/stringlib.htm。Google似乎表明Java没有快速的字符串搜索(例如,请参阅johannburkard.de/software/stringsearch),尽管我怀疑如果更改它会破坏任何内容。
邓肯,

32

当其他人提交了二次最坏情况下的时间复杂度解决方案时,我将添加一个线性解决方案(基于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

25

编辑:如果您发现了,可接受的答案显然比这更优雅和有效。如果我没有想过将原始字符串加倍,我会留下这个答案。


我只是蛮力。首先检查长度,然后尝试所有可能的旋转偏移。如果没有一个可以解决,请返回false-如果有一个可以解决,请立即返回true。

并不需要特别的连接-只需使用指针(C)或索引(Java)并在两个字符串中同时进行-从一个字符串的开头开始,在第二个字符串的当前候选旋转偏移处开始,并在必要时进行换行。在字符串的每个点检查字符是否相等。如果到达第一个字符串的末尾,就可以了。

连接起来大概很容易-尽管效率可能较低,至少在Java中是如此。


8
+1-我们不需要运行效率最高的解决方案3倍以上的优雅解决方案。这是C。微优化是定理的
斯蒂芬·C

8
采访者:洛塔说话,但我敢打赌这个家伙不会编码。
汉弗莱·鲍格

8
@Beau:如果有人想这样,欢迎他们问我代码。如果有人问我“我将如何做”,我通常会描述算法,而不是一味地编写代码。
乔恩·斯基特

3
@Jon-我读博的评论只是个玩笑
oxbow_lakes

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

您还可以将lookbehind与有限重复结合使用:

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

6
+1成为正则表达式大师。
克里斯·桑顿

-1将“ regex”和“ fun”放在同一语句中,而不用“ not”修饰“ fun”(只是在开玩笑,我没有拒绝投票)
Binary Worrier,2010年

-3表示正则表达式不好玩。
manlycode

谁能解释这个正则表达式“(。*)(。*)= \\ 2 \\ 1”的工作原理?
mawia 2010年

10

哇,哇...为什么每个人都为之兴奋O(n^2)呢?我很肯定我们可以在这里做得更好。上面的答案包括一个循环中的O(n)操作O(n)(substring / indexOf调用)。即使使用更有效的搜索算法;说Boyer-MooreKMP,最坏的情况仍然O(n^2)是重复。

一个O(n)随机的答案是简单的; 获取支持O(1)滑动窗口的哈希(如Rabin指纹);哈希字符串1,然后是哈希字符串2,然后继续在字符串周围移动哈希1的窗口,看看哈希函数是否冲突。

如果我们想象最坏的情况是诸如“扫描两条DNA链”之类的东西,那么发生碰撞的可能性就会上升,并且可能退化为类似之类的O(n^(1+e))东西(只是在这里猜测)。

最后,有一个确定性的O(nlogn)解决方案,它的外部常数很大。基本上,这个想法是对两个字符串进行卷积。卷积的最大值将是旋转差(如果旋转)。一O(n)检查确认。令人高兴的是,如果有两个相等的最大值,那么它们都是有效的解。您可以使用两个FFT和一个点积以及一个iFFT进行卷积nlogn + nlogn + n + nlogn + n == O(nlogn)

由于不能用零填充,也不能保证字符串的长度为2 ^ n,因此FFT不会是快速的。它们将是慢速的,O(nlogn)但仍比CT算法大得多的常数。

综上所述,我绝对是在O(n)这里有确定性解决方案的100%肯定的人,但我是否能找到它还是很胆小。


自身串联的字符串上的KMP(物理上或实际上用表示%stringsize)被保证为线性时间。
Kragen Javier Sitaker'4

拉宾卡普+1。与KMP不同,它使用恒定的空间,并且易于实现。(这也是我想到的第一个答案,在几秒钟内,很难看到“正确的”答案,因为这个答案就在那里,而且很贴心。)您的卷积思想使我想起了Shor的算法-我想知道是否存在亚线性量子解决方案-但这现在变得愚蠢了,对吧?
大流士培根

1
RK没有给出确定的O(n)解,而KMP在空间中是O(n),这可能是不希望的。查找双向或SMOA子字符串搜索,它们在时间上均为O(n),在空间上均为O(1)。顺便说一句,glibc strstr使用双向,但是如果您实际上连接字符串以使用它而不是使用%len,您将回到空间的O(n)。:-)
R .. GitHub停止帮助ICE 2010年

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”。
尼克·摩尔

5
在这段代码中,您将字符串传递了至少2次(如果不是3次)(在strlen和strcmp中)。您可以保存此检查,也可以将其保留在循环中。在循环时,如果一个字符串的字符数与另一个不同,请退出循环。您将知道长度,知道起点,也知道何时碰到空终止符。
纳斯科(Nasko)2010年

12
@Beau Martinez-因为有时执行时间比开发时间更重要:-)
phkahler 2010年

2
@phkahler-事情可能会更慢。其他语言中的内置索引函数通常使用快速字符串搜索算法,例如Boyer-Moore,Rabin-Karp或Knuth-Morris-Pratt。只是天真地重新编写C语言中的所有内容,并假设它会更快。
Thomas Ahle 2010年

8

这是一个O(n)适当的算法。它对<字符串的元素使用运算符。当然不是我的。我从这里拿走(该网站是波兰语。过去我偶然发现它,现在用英语找不到类似的东西,所以我展示一下我拥有的:))。

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)是刚刚SOOOOO从一个更深刻COMP-SCI的观点比任何非O(n)的溶液:)
SyntaxT3rr0r

4
+1表示时间最佳且代码大小(二进制和LoC)接近最佳的解决方案。有一个解释,这个答案会更好。
R .. GitHub停止帮助ICE,

莫名其妙。我们需要一个解释!
j_random_hacker 2011年

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

甚至使用index函数代替regex 更好:

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

1
你忘\Q/\Q$string2/
Kragen Javier Sitaker

3
\Q引用中的任何特殊字符$string2。没有它,.将被视为任何1个字符的字符串的旋转。
jackrabbit

6

不确定这是否是最有效的方法,但可能相对有趣Burrows-Wheeler变换。根据WP文章,输入的所有旋转都会产生相同的输出。对于诸如压缩之类的应用程序,这是不希望的,因此会指示原始旋转(例如,通过索引;请参阅该文章)。但是,对于简单的与旋转无关的比较,听起来很理想。当然,它不一定理想地有效!


由于Burrows-Wheeler变换涉及计算字符串的所有旋转,因此肯定不是最佳的。.:-)
R .. GitHub停止帮助ICE 2010年

6

将每个字符作为振幅并对其执行离散傅立叶变换。如果它们仅因旋转而不同,则频谱将在舍入误差范围内相同。当然,除非长度为2的幂,否则这是无效的,因此您可以执行FFT :-)


我们已将其用作有趣的编码练习,但我不确定我们是否可以对其进行评估;)。
jayshao 2011年

滥用了FFT :)我的+1
Aamir'2

5

尚无人提供模数方法,所以这里是一个:

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注意到了上面我的代码中的缺陷。当字符串中的第一个字符出现两次或更多次时,它将出错。例如,stackoverflow针对进行测试会owstackoverflow导致错误(应为true)。

感谢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

这是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

这是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

我认为您的答案不正确,因为int ndx = a.IndexOf(b [0]); 仅当字符串中没有其他具有相同b [0]值的元素时才有效。
piotr

感谢您注意到该漏洞。现在已更正
Michael Buen '04

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,

2

Opera的简单指针旋转技巧有效,但在运行时间最坏的情况下效率极低。只需想象一个字符串,其中包含许多长时间重复的字符,即:

S1 = HELLOHELLOHELLO1HELLOHELLOHELLO2

S2 = HELLOHELLOHELLO2HELLOHELLOHELLO1

在计算上,“循环直到出现不匹配,然后再加一然后重试”是一种可怕的方法。

为了证明您可以毫不费力地在普通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()的实现是特定于平台的,但是如果脑筋急转弯,总是可以用更快的替代方法(例如,博耶-摩尔算法)来代替)


1
您知道strstr()O(n + m)中的任何平台吗?另外,如果标准(或其他任何方法)不能保证您的线性运行时间为strstr(),则您不能断言整个算法具有线性时间兼容性。
jpalecek

这就是为什么我说可以用Boyer-Moore算法代替它,使其在线性时间内运行。
RarrRarrRarr

您的分配方法有两个潜在的问题s1SelfConcat:仅由于C9x,C允许可变的数组大小(尽管GCC允许更长的时间),并且在堆栈上分配大字符串时会遇到麻烦。Yosef Kreinin写了一篇非常有趣的博客文章。此外,使用Boyer-Moore,您的解决方案仍然是二次时间。你想要KMP。
Kragen Javier Sitaker


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

现在换个完全不同的东西。

如果您希望在某些约束条件下一个真正快速的答案,而字符串又不是彼此旋转的

  • 在两个字符串上计算一些基于字符的校验和(例如对所有字符进行异或运算)。如果签名不同,则字符串不是彼此旋转。

同意,它可能会失败,但它是非常快说,如果字符串不匹配,如果它们匹配,你仍然可以使用像字符串连接另一种算法来检查。


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

反转字符串之一。取两者的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

加入string1string2和使用KMP算法,以检查是否string2存在新组成的字符串。因为KMP的时间复杂度小于substr

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.