235

A friend of mine was asked the following question today at interview for the position of software developer:

Given two string s1 and s2 how will you check if s1 is a rotated version of s2 ?

Example:

If s1 = "stackoverflow" then the following are some of its rotated versions:

"tackoverflows"
"ackoverflowst"
"overflowstack"

where as "stackoverflwo" is not a rotated version.

The answer he gave was:

Take s2 and find the longest prefix that is a sub string of s1, that will give you the point of rotation. Once you find that point, break s2 at that point to get s2a and s2b, then just check if concatenate(s2a,s2b) == s1

It looks like a good solution to me and my friend. But the interviewer thought otherwise. He asked for a simpler solution. Please help me by telling how would you do this in Java/C/C++ ?

Thanks in advance.

Tim Post
  • 33,371
  • 15
  • 110
  • 174
Webdev
  • 2,317
  • 3
  • 16
  • 8
  • 4
    You don't have to check if concatenate(s2a,s2b) == s1, because you know s2a is equal to the beginning of s1. You can just check if s2b == substring of s1 from rotation_point to end. – Jason Hall Mar 31 '10 at 14:00
  • This reminds me of the fifteen puzzle, (taquin in french)... – jokoon Sep 27 '10 at 22:35
  • @Jason: No can do. If you only check "whether s2b == substring of s1" the program will give wrong answer in the case when s2b is actually the same characters as a substring of s2a. In other words, S2 = abcdabc and we are checking with S1=abcdefg. Clearly its not a rotation but in your case the program will say yes. This is because both S2a=abcd and S2b=abc are found individually in the string. – Mugen Oct 17 '10 at 20:08

26 Answers26

686

First make sure s1 and s2 are of the same length. Then check to see if s2 is a substring of s1 concatenated with 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

In Java:

boolean isRotation(String s1,String s2) {
    return (s1.length() == s2.length()) && ((s1+s1).indexOf(s2) != -1);
}
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
codaddict
  • 445,704
  • 82
  • 492
  • 529
  • 1
    Very nice. What I like most is that your answer is actually a good way of defining "is a rotation of". As a sidenote, you could also write "return len(s1) == len(s2) && substring(s2,concat(s1,s1));", but that's not necessarily better style, especially for such a short function. – Daniel Daranas Mar 31 '10 at 14:34
  • 49
    I like its elegance, but I had to think for a while to check there weren't any false positives. (I don't *think* there are.) – Jon Skeet Mar 31 '10 at 14:55
  • 2
    @Jon, @codaddict, if the same string is not considered a rotation, then all solutions on this page support false positives. That would be a good question to ask the interviewer, as well as if you are bounded by memory. – Nick Larsen Mar 31 '10 at 15:35
  • What the point of this solution? It's like saying "blah, my language has a function checkRotation()" and I'll use that. substring() is doing all the work. – MK. Mar 31 '10 at 15:38
  • 6
    You can also use `(s1+s1).contains(s2)` in Java. – polygenelubricants Mar 31 '10 at 15:52
  • 2
    @MK1 : Interview question such as these are usually used to check how the person would tackle a problem. – David Brunelle Mar 31 '10 at 17:21
  • 1
    Since it is a "how would you" question, not "what is a good algorithm to", this answer is appropriate. Otherwise, this would just be an innuendo for the follow up question "and how does that work?". – Svante Mar 31 '10 at 19:55
  • 4
    Anyway I would object a bit to this as an interview question. It has an "aha!" component, I think. Most programmers (me included) would just use brute force, which is not unreasonable anyway, and that may feel like not "clever" enough to the interviewer. – Daniel Daranas Mar 31 '10 at 20:18
  • surely its `s1 + s1.substring(0, s1.length() - 1)` as the concatenation? – oxbow_lakes Apr 01 '10 at 14:13
  • 5
    @Jon Concentrate on `s1+s1`. Clearly, all of its substrings with size `s1.length` are rotations of `s1`, by construction. Therefore, any string of size `s1.length` that is a substring of `s1+s1` must be a rotation of `s1`. – Daniel C. Sobral Apr 07 '10 at 03:08
  • I like checking the length first. An optimization to be sure, but simple, efficient and preventing possible false positives. – extraneon Apr 11 '10 at 14:10
  • 6
    @unicornaddict - what's great about this solution is it's so obvious once you point it out, I hate myself for not thinking of it! – James B Apr 30 '10 at 08:41
  • @extraneon: It's necessarry to check the length first, otherwise you get a false positive if s1 is a substring of s2. Given s2 = "Hello", s1="Hello World", then s2 is a substring of s1+s1, but s1 is not a rotation of s2. – Binary Worrier May 04 '10 at 14:19
  • 3
    +1: One one hand I'm quite pleased, this is exactly how I would have answered this question, on the other hand I feel slightly ill at the thoughts of 3k+ rep I could have reaped if I'd been first on the scene. Well done unicornaddict :) – Binary Worrier May 04 '10 at 14:31
  • 1
    It would be excellent if anybody could print a proof? – Thomas Ahle Jun 03 '10 at 10:14
  • 2
    +1, good answer. Can it be done without allocating new memory? – fastcodejava Sep 16 '10 at 11:08
  • I am curious though if we were to define 'is a rotation of' as function(or "operation") of String. Apparently it is commutative, i.e if s1 is a rotation of s2 then s2 is a rotation of s1. The answer covers this as well. Now, what if let's say, a String cannot be a rotation of itself, then we may have to add one more checking. Actually, even if a String _can_ be a rotation of itself, a checking on s1.equals(s2) would skip the concat part. An improvement performance wise maybe? – Adrian M Oct 26 '10 at 15:51
  • @codaddict +1 for the trick. It seems to be a nice utility method to be added in the String class but you may want to add add a check for s1 or s2 being null in which case just return false and thus avoid null pointer exception – sactiw Apr 26 '11 at 13:37
101

Surely a better answer would be, "Well, I'd ask the stackoverflow community and would probably have at least 4 really good answers within 5 minutes". Brains are good and all, but I'd place a higher value on someone who knows how to work with others to get a solution.

Chris Knight
  • 24,333
  • 24
  • 88
  • 134
49

Another python example (based on THE answer):

def isrotation(s1,s2):
     return len(s1)==len(s2) and s1 in 2*s2
Federico A. Ramponi
  • 46,145
  • 29
  • 109
  • 133
  • 1
    Interestingly I thought of duplicated `s2` rather than `s1` too... then realized that the relation was symmetric anyway. – Matthieu M. Apr 11 '10 at 11:34
  • 1
    If the string could be long, here's a Python version that uses Boyer-Moore to get O(n) running time: def isrotation(s1, s2): return len(s1)==len(s2) and re.compile(re.escape(s1)).search(2*s2) is not None – Duncan Apr 20 '10 at 13:15
  • 2
    @Duncan: does the `in` operator not use an O(n) algorithm? – Ken Bloom May 04 '10 at 14:21
  • The running time of the 'in' operator depends on the length of both strings. Consider `a in b` where `a` is `xxxxxxz` and b is a lot of x's: At best Python will compare len(b)-len(a) starting positions (I'm not sure here, it might just do len(b) comparisons) and len(a)-1 character comparisons from each location. Regular expressions with constant prefixes on the other hand do fewer comparisons (complicated to work out but apparently O(n) and often a lot fewer). – Duncan May 04 '10 at 19:04
  • 1
    @Duncan: The python string methods uses an optimized Boyer-Moore-Horspool. I wonder if Java has similar optimizations. – Thomas Ahle Jun 20 '11 at 23:28
  • 1
    @Thomas thanks for pointing that out. I had thought that only regular expressions used Boyer-Moore but I see I was wrong. For Python 2.4 and earlier my answer was correct but since Python 2.5 `s1 in s2` is optimised. See http://effbot.org/zone/stringlib.htm for the description of the algorithm. Google seems to indicate that Java doesn't have fast string searching (see http://johannburkard.de/software/stringsearch/ for example) though I doubt it would break anything if they changed it. – Duncan Jun 21 '11 at 09:18
32

As others have submitted quadratic worst-case time complexity solution, I'd add a linear one (based on the 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

Ry-
  • 218,210
  • 55
  • 464
  • 476
jpalecek
  • 47,058
  • 7
  • 102
  • 144
25

EDIT: The accepted answer is clearly more elegant and efficient than this, if you spot it. I left this answer as what I'd do if I hadn't thought of doubling the original string.


I'd just brute-force it. Check the length first, and then try every possible rotation offset. If none of them work out, return false - if any of them does, return true immediately.

There's no particular need to concatenate - just use pointers (C) or indexes (Java) and walk both along, one in each string - starting at the beginning of one string and the current candidate rotation offset in the second string, and wrapping where necessary. Check for character equality at each point in the string. If you get to the end of the first string, you're done.

It would probably be about as easy to concatenate - though probably less efficient, at least in Java.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 8
    +1 - we don't need no elegant solutions that run in 3+ times the most efficient solution. This is C ... micro-optimization is *de riguer*. – Stephen C Mar 31 '10 at 14:11
  • 1
    As this comes has come up before on stackoverflow, searching from the end of the string to the beginning provides a jumping mechanism which can greatly increase the speed of substring searches. Because of this, I would argue that it isn't much faster to run this in place, particularly with a brute force forward searching solution. – Nick Larsen Mar 31 '10 at 14:20
  • 8
    Interviewer: Lotta talk, but I bet this guy can't code. – Humphrey Bogart Mar 31 '10 at 14:50
  • @NickLarsen: I'm afraid I don't quite understand your comment. What exactly are you suggesting? – Jon Skeet Mar 31 '10 at 14:52
  • 8
    @Beau: If anyone wants to think that, they're welcome to ask me for code. If someone just asks me "how I would do something" I usually describe the algorithm rather than leaping to code. – Jon Skeet Mar 31 '10 at 14:57
  • 3
    @Jon - I read Beau's comment as being a joke – oxbow_lakes Mar 31 '10 at 15:04
  • 2
    @oxbow_lakes: Possibly. It's hard to tell. – Jon Skeet Mar 31 '10 at 15:18
  • 2
    @Jon Skeet There is a substring finding algorithm which searches from the end of the string to the front (http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm) which has a smaller coefficient than forward searching. You could implement it without the concatenation for this problem, but my point is that the elegant answer is on same magnitude of efficiency as what you suggest. – Nick Larsen Mar 31 '10 at 15:30
  • 37
    @Jon It was a joke! The interviewer doesn't interview Jon Skeet, Jon Skeet interviews him. – Humphrey Bogart Mar 31 '10 at 16:37
  • 2
    @NickLarsen: The elegant answer is certainly the way to go when you've spotted the trick. My answer is what I'd probably actually give in an interview though, if I didn't know the trick. I certainly wouldn't start implementing a complicated substring algorithm. – Jon Skeet Mar 31 '10 at 17:17
  • @Jon: that would be interesting to check efficiency of both implementations, my bet is that concatenating string is probably *more* efficient that the direct pointer solution, at least if you don't optimize the implementation for an unreasonable amount of time, even in Java. My rationale is that for the trivial solution you would call very simple heavily optimized library functions. – kriss May 19 '10 at 14:44
  • 1
    @kriss Jon's solution has O(n^2) worst case, so it's hardly a question which of them is faster. – Nikita Rybak Oct 21 '10 at 00:23
  • Personally, I'd say that figuring out tricks in an interview is almost an insurmountable feat. In that Case Jon's solution is one that comes to the mind most naturally. Yet again, reading the question on stack, with all the time in the world to present a beautiful solution, we got to give it to codaddict. The elegance of his solution may inspire many in their search for finding beautiful solutions elsewhere. Heck, that's why we are not computer engineers, we are computer scientists. Where the ingenuity of scientist meets the sheer wit of computer engineer :) – n0nChun Mar 08 '11 at 04:27
17

Here's one using regex just for fun:

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

You can make it a bit simpler if you can use a special delimiter character guaranteed not to be in either strings.

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

You can also use lookbehind with finite repetition instead:

boolean isRotation(String s1, String s2) {
   return (s1 + s2).matches(
      String.format("(.*)(.*)(?<=^.{%d})\\2\\1", s1.length())
   );
}
polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
10

Whoa, whoa... why is everyone so thrilled with an O(n^2) answer? I'm positive that we can do better here. THE answer above includes an O(n) operation in an O(n) loop (the substring/indexOf call). Even with a more efficient search algorithm; say Boyer-Moore or KMP, the worst-case is still O(n^2) with duplicates.

A O(n) randomized answer is straightforward; take a hash (like a Rabin fingerprint) that supports an O(1) sliding window; hash string 1, then hash string 2, and proceed to move the window for hash 1 around the string and see if the hash functions collide.

If we imagine the worst case being something like "scanning two strands of DNA", then the probability of collisions goes up, and this probably degenerates to something like O(n^(1+e)) or something (just guessing here).

Finally, there's a deterministic O(nlogn) solution that has a very big constant outside. Basically, the idea is to take a convolution of the two strings. The max value of the convolution will be the rotation difference (if they are rotated); an O(n) check confirms. The nice thing is that if there are two equal max values, then they are both also valid solutions. You can do the convolution with two FFT's and a dot product, and an iFFT, so nlogn + nlogn + n + nlogn + n == O(nlogn).

Since you can't pad with zeroes, and you can't guarantee that the strings are of 2^n length, the FFTs won't be the fast ones; they'll be the slow ones, still O(nlogn) but a much bigger constant than the CT algorithm.

All that said, I'm absolutely, 100% positive that there is a deterministic O(n) solution here, but darned if I can find it.

codaddict
  • 445,704
  • 82
  • 492
  • 529
user295691
  • 7,108
  • 1
  • 26
  • 35
  • KMP on the concatenated-with-itself string (either physically or virtually with a `%stringsize`) is guaranteed to be linear time. – Kragen Javier Sitaker Apr 23 '10 at 22:07
  • +1 for Rabin-Karp. Unlike KMP, it uses constant space, and it's simpler to implement. (It's also the first answer I thought of, in seconds, making it hard to see the 'right' answer, because this one's right there and it's sweet.) Your convolution idea reminds me of Shor's algorithm -- I wonder if there's a sublinear quantum solution -- but that's getting silly now, right? – Darius Bacon May 16 '10 at 07:26
  • 1
    RK does not give a deterministic O(n) solution, and KMP is O(n) in space which might be undesirable. Look up Two Way or SMOA substring searching which are both O(n) in time and O(1) in space. By the way, glibc strstr uses Two Way, but if you actually concatenate strings to use it as opposed to using %len you're back to O(n) in space. :-) – R.. GitHub STOP HELPING ICE Jun 28 '10 at 20:57
8

Fist, make sure the 2 strings have the same length. Then in C, you can do this with a simple pointer iteration.


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
  • 983
  • 1
  • 6
  • 17
  • 19
    Ah, C. Why do something in half the time and code when you can do it in C! – Humphrey Bogart Mar 31 '10 at 14:21
  • 11
    +1 It's very well written C. And to be fair, the question is tagged 'c'. – Nick Moore Mar 31 '10 at 14:30
  • 5
    In this code you have walked the strings at least 2 if not 3 times (in strlen and strcmp). You can save yourself this check and you can keep that logic in your loop. As you are looping, if one string character count is different than the other, exit the loop. You will know the lengths, as you know the start and you know when you've hit the null terminator. – Nasko Mar 31 '10 at 14:54
  • 12
    @Beau Martinez - because sometimes execution time is more important than development time :-) – phkahler Mar 31 '10 at 16:15
  • 2
    @phkahler - The thing is it might well be slower. The built in index functions in the other languages typically use a fast string search algorithm like Boyer-Moore, Rabin-Karp or Knuth-Morris-Pratt. It is too naive just reinvent everything in C, and assume it to be faster. – Thomas Ahle Jun 03 '10 at 10:32
8

Here is an O(n) and in place alghoritm. It uses < operator for the elements of the strings. It's not mine of course. I took it from here (The site is in polish. I stumbled upon it once in the past and I couldn't find something like that now in English, so I show what I have :)).

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;
}
codaddict
  • 445,704
  • 82
  • 492
  • 529
Maciej Hehl
  • 7,895
  • 1
  • 22
  • 23
7

I guess its better to do this in Java:

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

In Perl I would do:

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

or even better using the index function instead of the regex:

sub isRotation {
 my($string1,$string2) = @_;
 return length($string1) == length($string2) && index($string2,$string1.$string1) != -1;
}
Zacky112
  • 8,679
  • 9
  • 34
  • 36
6

Not sure if this is the most efficient method, but it might be relatively interesting: the the Burrows-Wheeler transform. According to the WP article, all rotations of the input yield the same output. For applications such as compression this isn't desirable, so the original rotation is indicated (e.g. by an index; see the article). But for simple rotation-independent comparison, it sounds ideal. Of course, it's not necessarily ideally efficient!

Edmund
  • 10,533
  • 3
  • 39
  • 57
6

Take each character as an amplitude and perform a discrete Fourier transform on them. If they differ only by rotation, the frequency spectra will be the same to within rounding error. Of course this is inefficient unless the length is a power of 2 so you can do an FFT :-)

phkahler
  • 5,687
  • 1
  • 23
  • 31
5

Nobody offered a modulo approach yet, so here's one:

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

Output:

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 noticed the flaw in my code above. It errors when the first character in the string occurs twice or more. For example, stackoverflow tested against owstackoverflow resulted in false, when it should be true.

Thanks piotr for spotting the error.

Now, here's the corrected code:

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

Here's the output:

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

Here's the lambda approach:

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

Here's the lambda approach output:

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
Community
  • 1
  • 1
Michael Buen
  • 38,643
  • 9
  • 94
  • 118
  • I don't think your answer is correct since int ndx = a.IndexOf(b[0]); will work only if there are not other elements with the same value of b[0] in the string. – piotr Apr 12 '10 at 09:28
  • thanks for noticing the flaw. corrected it now – Michael Buen Apr 12 '10 at 12:43
3

As no one has given a C++ solution. here it it:

bool isRotation(string s1,string s2) {

  string temp = s1;
  temp += s1;
  return (s1.length() == s2.length()) && (temp.find(s2) != string::npos);
}
codaddict
  • 445,704
  • 82
  • 492
  • 529
user324138
  • 31
  • 1
  • Couple points: you're doing the relatively expensive string concatenation even if the lengths don't match; you could pass s2 by const reference. – Tony Delroy Jan 21 '11 at 07:04
2

Opera's simple pointer rotation trick works, but it is extremely inefficient in the worst case in running time. Simply imagine a string with many long repetitive runs of characters, ie:

S1 = HELLOHELLOHELLO1HELLOHELLOHELLO2

S2 = HELLOHELLOHELLO2HELLOHELLOHELLO1

The "loop until there's a mismatch, then increment by one and try again" is a horrible approach, computationally.

To prove that you can do the concatenation approach in plain C without too much effort, here is my solution:

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

This is linear in running time, at the expense of O(n) memory usage in overhead.

(Note that the implementation of strstr() is platform-specific, but if particularly brain-dead, can always be replaced with a faster alternative such as the Boyer-Moore algorithm)

Community
  • 1
  • 1
RarrRarrRarr
  • 3,712
  • 1
  • 20
  • 14
  • 1
    Do you know of any platform that has `strstr()` in O(n+m)? Also, if the standard (or anything else) doesn't guarantee you a linear running time of `strstr()`, you cannot assert that the whole algorithm has linear time compexity. – jpalecek Apr 01 '10 at 22:44
  • Which is why I said that it can be replaced by the Boyer-Moore algorithm, making it run in linear time. – RarrRarrRarr Apr 01 '10 at 22:56
  • There are a couple of potential problems with your method of allocating `s1SelfConcat`: it's only since C9x that C allows variable array sizes (although GCC has allowed it much longer), and you will run into trouble allocating large strings on the stack. Yosef Kreinin wrote [a very amusing blog post](http://www.yosefk.com/blog/the-c-sucks-series-petrifying-functions.html) about this problem. Also, your solution is still quadratic time with Boyer-Moore; you want KMP. – Kragen Javier Sitaker Apr 23 '10 at 22:03
2

C#:

s1 == null && s2 == null || s1.Length == s2.Length && (s1 + s1).Contains(s2)
Anthony Faull
  • 17,549
  • 5
  • 55
  • 73
2

I like THE answer that checks if s2 is a substring of s1 concatenated with s1.

I wanted to add an optimization that doesn't lose its elegance.

Instead of concatenating the strings you can use a join view (I don't know for other language, but for C++ Boost.Range provide such kind of views).

As the check if a string is a substring of another has linear average complexity (Worst-case complexity is quadratic), this optimization should improve the speed by a factor of 2 in average.

Vicente Botet Escriba
  • 4,305
  • 1
  • 25
  • 39
2

A pure Java answer (sans null checks)

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;
}
ring bearer
  • 20,383
  • 7
  • 59
  • 72
2

And now for something completely different.

If you want a really fast answer in some constrained context when strings are not rotation of one another

  • compute some character based checksum (like xoring all characters) on both strings. If signatures differ strings are not rotations of one another.

Agreed, it can fail, but it is very fast to say if strings don't match and if they match you can still use another algorithm like string concatenation to check.

kriss
  • 23,497
  • 17
  • 97
  • 116
1

Another Ruby solution based on the answer:

def rotation?(a, b); a.size == b.size and (b*2)[a]; end
Community
  • 1
  • 1
Anurag
  • 140,337
  • 36
  • 221
  • 257
1

It's very easy to write in PHP using strlen and strpos functions:

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

I don't know what strpos uses internally, but if it uses KMP this will be linear in time.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user325894
  • 183
  • 1
  • 7
1

Reverse one of the strings. Take the FFT of both (treating them as simple sequences of integers). Multiply the results together point-wise. Transform back using inverse FFT. The result will have a single peak if the strings are rotations of each other -- the position of the peak will indicate by how much they are rotated with respect to each other.

brewbuck
  • 887
  • 6
  • 9
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;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

Why not something like this?


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

Of course, you could write your own IndexOf() function; I'm not sure if .NET uses a naive way or a faster way.

Naive:


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

Faster:


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

Edit: I might have some off-by-one problems; don't feel like checking. ;)

hehewaffles
  • 582
  • 5
  • 17
0

I'd do this in Perl:

sub isRotation { 
     return length $_[0] == length $_[1] and index($_[1],$_[0],$_[0]) != -1; 
}
gameover
  • 11,813
  • 16
  • 59
  • 70
0

Join string1 with string2 and use KMP algorithm to check whether string2 is present in newly formed string. Because time complexity of KMP is lesser than substr.

codaddict
  • 445,704
  • 82
  • 492
  • 529
CrazyCoder
  • 2,465
  • 8
  • 36
  • 57