【问题标题】:Interview question: Check if one string is a rotation of other string [closed]面试问题:检查一个字符串是否是另一个字符串的旋转[关闭]
【发布时间】:2011-02-02 22:56:10
【问题描述】:

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

给定两个字符串s1s2,你将如何检查s1 是否是s2旋转 版本?

示例:

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

"tackoverflows"
"ackoverflowst"
"overflowstack"

"stackoverflwo" 不是旋转版本。

他给出的答案是:

获取s2 并找到最长的前缀,即s1 的子字符串,这将为您提供旋转点。一旦你找到那个点,在那个点打破s2得到s2as2b,然后检查concatenate(s2a,s2b) == s1是否

对我和我的朋友来说,这似乎是一个很好的解决方案。但面试官不这么认为。他要求一个更简单的解决方案。请告诉我您将如何在Java/C/C++ 中执行此操作?

提前致谢。

【问题讨论】:

  • 你不必检查 concatenate(s2a,s2b) == s1,因为你知道 s2a 等于 s1 的开头。您可以只检查 s2b == 从 rotation_point 到 end 的 s1 子字符串。
  • 这个问题和最佳答案是如何获得这么多赞的!?
  • @David:因为它很有趣。
  • 我会说,非常有趣且优雅、简单的答案。
  • @David:因为这是一个在此之前没有被问过的问题,也是每个人 理解的问题(如果有人不理解这个问题/答案,通常肯定不会支持它;一个非常简单的问题有更广泛的受众)并且还因为它被标记为 Java 和 C。它很重要 :)

标签: java c++ c


【解决方案1】:

首先确保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);
}

【讨论】:

  • 我喜欢它的优雅,但我不得不考虑一段时间以检查没有任何误报。 (我不认为有。)
  • 你也可以在Java中使用(s1+s1).contains(s2)
  • 无论如何我会反对这个作为面试问题。它有一个“啊哈!”组件,我想。大多数程序员(包括我)只会使用蛮力,这无论如何都不是不合理的,而且可能会让面试官觉得不够“聪明”。
  • @Jon 专注于s1+s1。显然,它的所有大小为s1.length 的子字符串都是s1 的旋转,通过构造。因此,任何大小为s1.length 的字符串是s1+s1 的子字符串,都必须是s1 的旋转。
  • @unicornaddict - 这个解决方案的优点是一旦你指出它就很明显,我恨自己没有想到它!
【解决方案2】:

当然更好的答案是,“好吧,我会询问 stackoverflow 社区,并且可能会在 5 分钟内得到至少 4 个非常好的答案”。头脑很好,但我更看重知道如何与他人合作以找到解决方案的人。

【讨论】:

  • +1 纯粹的脸颊。让我开心:-)
  • 如果他们不同意,您可以将他们链接到这个问题。
  • 在面试时掏出手机可能会被认为是不礼貌的,最终他们会雇用 Jon Skeet。
  • 这实际上可能正是我想说的
  • 我认为他们买不起 Jon Skeet。
【解决方案3】:

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

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

【讨论】:

  • 有趣的是,我还想到了重复的s2 而不是s1...然后意识到这种关系无论如何都是对称的。
  • 如果字符串可能很长,这里有一个 Python 版本,它使用 Boyer-Moore 来获得 O(n) 运行时间: def isrotation(s1, s2): return len(s1)==len( s2) 和 re.compile(re.escape(s1)).search(2*s2) 不是 None
  • @Duncan:in 运算符不使用 O(n) 算法吗?
  • @Duncan:python 字符串方法使用优化的 Boyer-Moore-Horspool。不知道Java有没有类似的优化。
  • @Thomas 感谢您指出这一点。我原以为只有正则表达式才使用 Boyer-Moore,但我发现我错了。对于 Python 2.4 及更早版本,我的答案是正确的,但由于 Python 2.5 s1 in s2 已优化。算法描述见effbot.org/zone/stringlib.htm。谷歌似乎表明 Java 没有快速的字符串搜索(例如参见 johannburkard.de/software/stringsearch),但我怀疑如果他们改变它会破坏任何东西。
【解决方案4】:

由于其他人已经提交了二次最坏情况时间复杂度解决方案,我将添加一个线性解决方案(基于KMP Algorithm):

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

working example

【讨论】:

  • ideone.com +1 - 看起来很有趣!
【解决方案5】:

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


我只是蛮力的。首先检查长度,然后尝试所有可能的旋转偏移。如果它们都不起作用,则返回 false - 如果其中任何一个起作用,则立即返回 true。

没有特别需要连接 - 只需使用指针 (C) 或索引 (Java) 并一起走,每个字符串中一个 - 从一个字符串的开头开始,第二个字符串中的当前候选旋转偏移量,并且必要时包装。检查字符串中每个点的字符相等性。如果你到达第一个字符串的末尾,你就完成了。

它可能很容易连接 - 尽管效率可能较低,至少在 Java 中是这样。

【讨论】:

  • +1 - 我们不需要运行 3 倍以上最有效解决方案的优雅解决方案。这是C ...微优化是de riguer
  • 采访者:很多话,但我敢打赌这家伙不会编码。
  • @Beau:如果有人想这样想,欢迎向我索要代码。如果有人只是问我“我将如何做某事”,我通常会描述算法而不是跳到代码。
  • @Jon - 我认为 Beau 的评论是在开玩笑
  • @Jon 这是个玩笑!面试官没有采访 Jon Skeet,Jon Skeet 采访了他。
【解决方案6】:

这是一个使用正则表达式的例子:

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

【讨论】:

  • +1 正则表达式大师。
  • -1 将“regex”和“fun”这两个词放在同一个语句中,而不用“not”修改“fun”(开玩笑的,我没有投反对票)
  • -3 表示正则表达式不好玩。
  • 能否请任何人解释一下这个正则表达式 "(.*)(.*)=\\2\\1" 是如何工作的!
【解决方案7】:

哇,哇...为什么每个人都对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 算法大得多。

话虽如此,我绝对 100% 肯定这里有一个确定性的 O(n) 解决方案,但如果我能找到它,那该死的。

【讨论】:

  • KMP 与自身连接的字符串(无论是物理上还是虚拟上都带有%stringsize)保证是线性时间。
  • 拉宾-卡普+1。与 KMP 不同,它使用常量空间,并且更易于实现。 (这也是我在几秒钟内想到的第一个答案,这使得很难看到“正确”的答案,因为这个答案就在那里,而且很甜蜜。)你的卷积想法让我想起了 Shor 的算法——我想知道是否存在次线性量子解决方案——但现在越来越傻了,对吧?
  • RK 没有给出确定性的 O(n) 解决方案,并且 KMP 在空间中是 O(n),这可能是不可取的。查找双向或 SMOA 子字符串搜索,时间上为 O(n),空间上为 O(1)。顺便说一句,glibc strstr 使用 Two Way,但是如果你实际上连接字符串来使用它而不是使用 %len,那么你在空间中回到了 O(n)。 :-)
【解决方案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);
}

【讨论】:

  • 啊,C。既然可以在 C 中完成,为什么要花一半的时间和代码!
  • +1 C 写得很好。公平地说,这个问题被标记为“c”。
  • 在这段代码中,如果不是 3 次(在 strlen 和 strcmp 中),您至少已遍历字符串 2 次。您可以保存此检查,并且可以将该逻辑保留在循环中。在循环时,如果一个字符串字符数与另一个不同,则退出循环。您将知道长度,因为您知道开始,并且知道何时遇到空终止符。
  • @Beau Martinez - 因为有时执行时间比开发时间更重要 :-)
  • @phkahler - 问题是它可能会更慢。其他语言中的内置索引函数通常使用快速字符串搜索算法,如 Boyer-Moore、Rabin-Karp 或 Knuth-Morris-Pratt。用 C 重新发明一切,并假设它更快,这太天真了。
【解决方案9】:

这是一个O(n) 和就地算法。它对字符串的元素使用&lt; 运算符。这当然不是我的。我从here 拿的(该网站是波兰语。我过去偶然发现过一次,现在找不到类似的英文内容,所以我展示了我所拥有的 :))。

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 的角度来看只是 sooooo 更深刻比任何非 O(n) 解决方案 :)
  • +1 表示时间最优且代码大小接近最优(二进制和 LoC)的解决方案。如果有解释,这个答案会更好。
  • 完全莫名其妙。我们需要一个解释!
【解决方案10】:

我想在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 函数而不是正则表达式:

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

【讨论】:

  • 您在/\Q$string2/ 中忘记了\Q
  • \Q 引用 $string2 中的任何特殊字符。没有它,. 将被认为是任何 1 个字符的字符串的旋转。
【解决方案11】:

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

【讨论】:

  • 由于 Burrows-Wheeler 变换涉及计算字符串的所有旋转,它肯定不会是最优的.. :-)
【解决方案12】:

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

【讨论】:

  • 我们把它当作一个有趣的编码练习,我不确定我们是否能够评估它;)。
  • FFT 被滥用 :) +1 来自我
【解决方案13】:

还没有人提供模数方法,所以这里有一个:

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 注意到我上面代码中的缺陷。当字符串中的第一个字符出现两次或更多次时,它会出错。例如,stackoverflowowstackoverflow 测试结果为假,而它应该为真。

感谢 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] 值的其他元素时才有效。
  • 感谢您发现该缺陷。现在更正它
【解决方案14】:

因为没有人给出 C++ 解决方案。在这里:

bool isRotation(string s1,string s2) {

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

【讨论】:

  • 两点:即使长度不匹配,您也在进行相对昂贵的字符串连接;您可以通过 const 引用传递 s2。
【解决方案15】:

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() 的实现是特定于平台的,但如果特别脑残,总是可以用更快的替代方案代替,例如 Boyer-Moore 算法)

【讨论】:

  • 你知道在 O(n+m) 中有strstr() 的任何平台吗?此外,如果标准(或其他任何标准)不能保证strstr() 的线性运行时间,则不能断言整个算法具有线性时间复杂性。
  • 所以我说可以用Boyer-Moore算法代替,让它在线性时间内运行。
  • 您分配s1SelfConcat 的方法存在一些潜在问题:只有从C9x 开始,C 才允许可变数组大小(尽管GCC 允许它更长),您会遇到麻烦在堆栈上分配大字符串。 Yosef Kreinin 就这个问题写了a very amusing blog post。此外,您的解决方案仍然是 Boyer-Moore 的二次时间;你想要 KMP。
【解决方案16】:

C#:

s1 == null && s2 == null || s1.Length == s2.Length && (s1 + s1).Contains(s2)

【讨论】:

    【解决方案17】:

    我喜欢检查 s2 是否是 s1 与 s1 连接的子字符串的答案。

    我想添加一个不会失去其优雅性的优化。

    您可以使用连接视图代替连接字符串(我不知道其他语言,但对于 C++ Boost.Range 提供了这种视图)。

    由于检查一个字符串是否是另一个字符串的子字符串具有线性平均复杂度(最坏情况复杂度是二次的),因此这种优化应该平均将速度提高 2 倍。

    【讨论】:

      【解决方案18】:

      纯 Java 答案(无空检查)

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

      【讨论】:

        【解决方案19】:

        现在来点完全不同的东西。

        如果您想在字符串相互旋转时在某些受限上下文中获得真正快速的答案

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

        同意,它可能会失败,但是非常快速判断字符串是否不匹配,如果它们匹配,您仍然可以使用其他算法(如字符串连接)进行检查。

        【讨论】:

          【解决方案20】:

          另一个基于the的Ruby解决方案@答案:

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

          【讨论】:

            【解决方案21】:

            使用 strlenstrpos 函数在 PHP 中编写非常容易:

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

            我不知道strpos 内部使用什么,但如果它使用KMP,这将是线性时间。

            【讨论】:

              【解决方案22】:

              反转其中一个字符串。取两者的 FFT(将它们视为简单的整数序列)。将结果逐点相乘。使用逆 FFT 变换回来。如果字符串相互旋转,结果将有一个峰值 - 峰值的位置将指示它们相对于彼此旋转的程度。

              【讨论】:

                【解决方案23】:

                为什么不这样呢?

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

                编辑:我可能会遇到一些问题;不想检查。 ;)

                【讨论】:

                  【解决方案24】:

                  我会在 Perl 中这样做:

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

                  【讨论】:

                    【解决方案25】:
                    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;
                    }
                    

                    【讨论】:

                      【解决方案26】:

                      string1string2 连接并使用KMP algorithm 来检查string2 是否存在于新形成的字符串中。因为KMP的时间复杂度小于substr

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2017-04-30
                        • 1970-01-01
                        • 2019-05-11
                        • 1970-01-01
                        • 2012-08-15
                        • 2011-12-16
                        • 2013-05-12
                        相关资源
                        最近更新 更多