면접 질문 : 한 문자열이 다른 문자열의 회전인지 확인


235

소프트웨어 개발자의 지위에 대한 인터뷰에서 내 친구가 오늘 다음과 같은 질문을 받았습니다.

두 개의 문자열을 감안 s1하고 s2어떻게되는지 확인한다 s1A는 회전 의 버전 s2?

예:

그렇다면 s1 = "stackoverflow"다음은 회전 된 버전 중 일부입니다.

"tackoverflows"
"ackoverflowst"
"overflowstack"

곳으로 "stackoverflwo"입니다 하지 회전 된 버전.

그가 준 대답은 다음과 같습니다.

s2하위 문자열 인 가장 긴 접두사를 가져 와서 s1회전 점을 찾습니다 . 당신이 그 지점을 찾으면, 휴식 s2그 시점에서 취득하는 s2a하고 s2b, 그럼 그냥 있는지 확인concatenate(s2a,s2b) == s1

나와 내 친구에게 좋은 해결책처럼 보입니다. 그러나 면접관은 다른 생각을했습니다. 그는 더 간단한 해결책을 요구했습니다. 이 작업을 수행하는 방법을 알려주십시오.Java/C/C++ 하시겠습니까?

미리 감사드립니다.


4
s2a가 s1의 시작과 같기 때문에 concatenate (s2a, s2b) == s1인지 확인할 필요가 없습니다. s2b == s1의 하위 문자열이 rotation_point에서 end까지 있는지 확인할 수 있습니다.
Jason Hall

33
이 질문들과 최고의 답변은 어떻게 많은 찬사를 얻었습니까!?
David Johnstone

9
@David : 흥미 롭기 때문입니다.
Cam

6
나는 매우 흥미롭고 우아하고 간단한 대답이라고 말할 것입니다.
Guru

7
@David : 여기에 묻지 않은 질문과 모든 사람이 이해 하는 질문이기 때문에 (질문 / 답변을 이해하지 못하면 보통 그것을 피하지 않을 것입니다. 꽤 간단한 질문은 더 많은 청중이 있습니다) 이것은 자바와 C로 태그되어 있기 때문입니다. :)
BalusC

답변:


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

자바에서 :

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

49
나는 그 우아함을 좋아하지만, 오 탐지가 없는지 확인하기 위해 잠시 생각해야했습니다. (나는 그렇게 생각 하지 않습니다 .)
Jon Skeet

6
(s1+s1).contains(s2)Java 에서도 사용할 수 있습니다 .
polygenelubricants

4
어쨌든 나는 인터뷰 질문으로 이것에 대해 약간의 이의를 제기 할 것입니다. "아하!" 생각합니다. 대부분의 프로그래머 (포함)는 무차별 적이 지 않은 무차별 대입을 사용하여 면접관에게 충분히 "영리한"느낌이 들지 않을 수 있습니다.
Daniel Daranas

5
@Jon Concentrate on s1+s1. 분명히, 크기 s1.length가있는 모든 하위 문자열 s1은 구성에 의한 회전입니다 . 따라서 s1.length부분 문자열 인 크기 의 문자열은 s1+s1로테이션이어야합니다 s1.
Daniel C. Sobral

6
@unicornaddict-이 솔루션의 장점은 일단 지적하면 너무 분명하다는 것입니다. 생각하지 않으려는 자신이 싫어요!
제임스 B

101

더 나은 대답은 "글쎄, 나는 stackoverflow 커뮤니티에 물어볼 것이고 아마도 5 분 안에 적어도 4 개의 정말로 좋은 답변을 얻을 것이다"라고 말할 것이다. 두뇌는 모두 훌륭하지만, 다른 사람들과 협력하여 솔루션을 얻는 방법을 알고있는 사람에게는 더 높은 가치를 부여합니다.


14
얇은 뺨에 +1 My day :-)
Platinum Azure

5
그들이 동의하지 않으면, 당신은 그것들을이 질문에 연결할 수 있습니다.
Cam

51
인터뷰 중에 핸드폰을 꺼내는 것은 무례한 것으로 간주 될 수 있으며 결국 존 스케이트 (Jon Skeet)를 고용하게됩니다.
tstenner

2
실제로 아마 내가 말한 것
Chris Dutrow

6
나는 그들이 존 스케이트를 감당할 수있을 것 같지 않다.
SolutionYogi

49

또 다른 파이썬 예제 (The 답변을 기반으로) :

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) : return len (s1) == len (s2) 및 re.compile (re .escape (s1)). search (2 * s2)는 없음이 아닙니다
Duncan

2
@ Duncan : in연산자가 O (n) 알고리즘을 사용 하지 않습니까?
Ken Bloom

1
@ Duncan : 파이썬 문자열 메소드는 최적화 된 Boyer-Moore-Horspool을 사용합니다. Java가 비슷한 최적화를 가지고 있는지 궁금합니다.
Thomas Ahle

1
@Thomas 지적 해 주셔서 감사합니다. 정규식 만 Boyer-Moore를 사용한다고 생각했지만 잘못되었습니다. Python 2.4 및 이전 버전에서는 내 대답이 정확했지만 Python 2.5 이후 s1 in s2최적화되었습니다. 알고리즘에 대한 설명은 effbot.org/zone/stringlib.htm 을 참조하십시오 . 구글은 자바가 빠른 문자열 검색을 가지고 있지 않다고 지적하는 것 같지만 ( 예를 들어 johannburkard.de/software/stringsearch 참조 ) 그것이 바뀌면 아무것도 깨뜨릴 것이라고 의심합니다.
Duncan

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

25

편집 : 당신이 그것을 발견하면 허용 된 대답은 이것보다 분명히 우아하고 효율적입니다. 원래 문자열을 두 배로 늘릴 생각이 없다면이 답변을 내가 한 일로 남겨 두었습니다.


난 그냥 그것을 무차별 강제합니다. 먼저 길이를 확인한 다음 가능한 모든 회전 오프셋을 시도하십시오. 그들 중 어느 것도 해결되지 않으면 거짓을 반환하십시오-그들 중 하나라도 있으면 즉시 true를 반환하십시오.

연결 할 필요가 없습니다. 포인터 (C) 또는 인덱스 (Java)를 사용하고 각 문자열마다 하나씩 따라 가십시오. 한 문자열의 시작 부분부터 시작하여 두 번째 문자열의 현재 후보 회전 오프셋을 시작하고 필요한 경우 줄 바꿈하십시오. . 문자열의 각 지점에서 문자가 같은지 확인하십시오. 첫 번째 문자열의 끝에 도달하면 완료된 것입니다.

적어도 자바에서는 아마도 연결하기가 쉬울 것입니다.


8
+1-가장 효율적인 솔루션의 3 배 이상 실행되는 우아한 솔루션이 필요하지 않습니다. 이것은 C입니다 ... 마이크로 최적화는 riguer 입니다.
Stephen C

8
면담 자 : Lotta가 이야기하지만이 사람은 코드를 작성할 수 없습니다.
Humphrey Bogart

8
@Beau : 누구든지 그렇게 생각하고 싶다면, 코드를 요청해도됩니다. 누군가가 "어떻게해야합니까?"
Jon Skeet

3
@ Jon-나는 농담으로 Beau의 의견을 읽었습니다
oxbow_lakes

37
@Jon 농담이었습니다! 면접관은 Jon Skeet을 인터뷰하지 않고 Jon Skeet은 그를 인터뷰합니다.
Humphrey Bogart

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
Chris Thornton

-1 "regex"와 "fun"이라는 단어를 "not"으로 수정하지 않고 "unex"와 "fun"을 같은 문장에 넣는 경우 (농담만으로 투표하지 않았습니다)
Binary Worrier

정규식이 재미 있지 않다는 것을 의미하는 -3.
manlycode

이 정규 표현식 "(. *) (. *) = \\ 2 \\ 1"의 작동 방식을 설명 할 수 있습니까?
mawia

10

우와, 우와 ... 왜 모든 사람들이 O(n^2)답에 감격 합니까? 우리가 여기서 더 잘할 수 있다고 생각합니다. 위의 답변에는 루프 (substring / indexOf 호출) O(n)작업이 포함되어 O(n)있습니다. 보다 효율적인 검색 알고리즘으로도; 말을 Boyer-Moore하거나 KMP, 최악의 경우는 여전히O(n^2) 중복으로.

O(n)무작위 대답은 간단하다; Rabin 지문과 같은 해시를 사용하여O(1)슬라이딩 윈도우 . 해시 문자열 1, 해시 문자열 2, 그리고 문자열 주위로 해시 1의 창을 이동하고 해시 함수가 충돌하는지 확인하십시오.

최악의 경우가 "두 가닥의 DNA 스캔"과 같은 것으로 생각되면 충돌 가능성이 높아지고 아마도 O(n^(1+e))여기에서 추측 하는 것과 같은 것으로 저하 될 수 있습니다.

마지막으로 결정적인 O(nlogn)솔루션은 외부에서 매우 큰 상수를 갖습니다. 기본적으로 아이디어는 두 줄의 컨볼 루션을 취하는 것입니다. 컨벌루션의 최대 값은 회전 차이 (회전 한 경우)입니다. O(n)체크 확인한다. 좋은 점은 두 개의 동일한 최대 값이 있으면 둘 다 유효한 솔루션이라는 것입니다. 두 개의 FFT와 내적, iFFT로 컨볼 루션을 수행 할 수 있습니다 nlogn + nlogn + n + nlogn + n == O(nlogn).

0으로 채울 수 없으며 문자열의 길이가 2 ^ n임을 보장 할 수 없으므로 FFT는 빠른 것이 아닙니다. 그들은 여전히 ​​느린 것입니다O(nlogn) 만 CT 알고리즘보다 훨씬 더 큰 상수입니다.

내가 말한 O(n)것은, 여기에 결정적 솔루션 이 있다고 100 % 긍정적 이지만, 그것을 찾을 수 있다면 감히.


자체 연결 문자열 (물리적 또는 가상으로 %stringsize)의 KMP 는 선형 시간이어야합니다.
Javier

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 중지 지원 얼음

8

주먹, 두 줄의 길이가 같은지 확인하십시오. 그런 다음 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로 할 수있는 시간과 코드를 절반으로 줄인 이유는 무엇입니까!
Humphrey Bogart

11
+1 C로 잘 쓰여져 있습니다. 공정하게 말하면 'c'로 표시됩니다.
Nick Moore

5
이 코드에서는 문자열을 3 번이 아닌 경우 2 번 이상 걸었습니다 (strlen 및 strcmp). 이 검사를 저장하고 루프에서 해당 논리를 유지할 수 있습니다. 루핑 할 때 한 문자열 문자 수가 다른 문자열 문자 수와 다른 경우 루프를 종료하십시오. 시작을 알고 널 터미네이터를 칠 때 알면 길이를 알 수 있습니다.
스코

12
@Beau Martinez-개발 시간보다 실행 시간이 더 중요하기 때문에 :-)
phkahler

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)은 그냥 sooooo는 더 깊은 A로부터 COMP-SCI의 비보다 관점 O (N) : 용액
SyntaxT3rr0r

4
코드 크기 (2 진 및 LoC 모두)에서 시간에 최적이고 거의 최적 인 솔루션의 경우 +1입니다. 이 대답은 설명으로 더 좋습니다.
R .. GitHub 중지 지원 얼음

완전히 당황합니다. 설명이 필요합니다!
j_random_hacker

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

3
\Q의 특수 문자를 인용합니다 $string2. 이것이 없으면 .1 자 문자열의 회전으로 간주됩니다.
jackrabbit

6

이것이 가장 효율적인 방법인지 확실하지 않지만 Burrows-Wheeler 변환 과 같이 비교적 흥미로울 수 있습니다 . WP 기사에 따르면 입력의 모든 회전은 동일한 출력을 산출합니다. 압축과 같은 응용 분야에서는 바람직하지 않으므로 원래 회전이 표시됩니다 (예 : 색인, 기사 참조). 그러나 간단한 회전 독립적 비교를 위해서는 이상적으로 들립니다. 물론 반드시 이상적으로 효율적인 것은 아닙니다!


버로우 - 휠러는 문자열의 모든 회전을 계산 포함 변환하기 때문에, 반드시 최적 않을거야 .. :-)
R을 ... GitHub의 STOP은 ICE 돕기

6

각 문자를 진폭으로 사용하여 개별 푸리에 변환을 수행하십시오. 회전에 의해서만 다른 경우, 주파수 스펙트럼은 반올림 오차 내에서 동일합니다. 물론 길이가 2의 거듭 제곱이 아닌 한 비효율적이므로 FFT를 수행 할 수 있습니다 :-)


우리는 이것을 흥미로운 코딩 연습으로 사용했지만, 우리가 그것을 평가할 수 있을지 모르겠습니다.;).
jayshao

FFT 남용 :) +1
Aamir

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 결과가 참이어야 할 때 거짓이되었습니다.

오류를 발견해 주셔서 감사합니다.

이제 올바른 코드는 다음과 같습니다.

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

결함을 발견해 주셔서 감사합니다. 지금 수정
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 2012 년

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 ()의 구현은 플랫폼에 따라 다르지만 특히 브레인 데드 인 경우 항상 Boyer-Moore 알고리즘과 같은 더 빠른 대안으로 대체 할 수 있습니다)


1
strstr()O (n + m) 에있는 플랫폼을 알고 있습니까? 또한 표준 (또는 다른 것)이의 선형 실행 시간을 보장하지 않는 strstr()경우 전체 알고리즘에 선형 시간 compexity가 있다고 주장 할 수 없습니다.
jpalecek

그래서 Boyer-Moore 알고리즘으로 대체하여 선형 시간으로 실행할 수 있다고 말했습니다.
RarrRarrRarr

할당 방법에는 몇 가지 잠재적 인 문제가 있습니다 s1SelfConcat.C9x 이후에 C가 가변 배열 크기를 허용하지만 (GCC가 훨씬 더 오래 허용하더라도) 스택에 큰 문자열을 할당하는 데 어려움을 겪을 수 있습니다. Yosef Kreinin은 매우 재미있는 블로그 게시물을 작성했습니다. 은이 문제에 대해 . 또한 귀하의 솔루션은 여전히 ​​Boyer-Moore와 2 차적인 시간입니다. 당신은 KMP를 원합니다.
Kragen Javier Sitaker


2

s2가 s1과 연결된 s1의 하위 문자열인지 확인하는 대답이 마음에 듭니다.

우아함을 잃지 않는 최적화를 추가하고 싶었습니다.

문자열을 연결하는 대신 조인 뷰를 사용할 수 있습니다 (다른 언어는 모르지만 C ++ Boost.Range는 이러한 종류의 뷰를 제공합니다).

문자열이 다른 문자열의 하위 문자열인지 확인하면 선형 평균 복잡도 (가장 복잡한 경우 2 차)가 있으므로이 최적화는 속도를 평균 2 배 향상시켜야합니다.


2

순수한 자바 답변 (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;
}

2

그리고 지금 완전히 다른 무언가를 위해.

문자열이 서로 회전 하지 않을 때 제한된 컨텍스트에서 실제로 빠른 대답을 원한다면

  • 두 문자열에서 일부 문자 기반 체크섬 (모든 문자 xoring 등)을 계산합니다. 서명이 다른 경우 문자열은 서로 회전하지 않습니다.

동의하지만 실패 할 수는 있지만 문자열이 일치하지 않으면 말하는 것이 매우 빠르며 일치하는 경우 문자열 연결과 같은 다른 알고리즘을 사용하여 확인할 수 있습니다.


1

답변을 기반으로 또 다른 루비 솔루션 :

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

KMP 알고리즘 에 참여 string1하여 string2이를 사용 하여 새로 형성된 문자열에 있는지 확인하십시오 . KMP의 시간 복잡성은보다 작기 때문 입니다.string2substr

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.