O (n)에서 접미사 배열을 사용하여 문자열의 최소 사전 회전


9

ACM 2003에서 문제를 인용하겠습니다.

길이 n의 문자열 (1 <= n <= 100000)을 고려하십시오. 최소 사전 사전 회전을 결정하십시오. 예를 들어 문자열 "alabala"의 회전은 다음과 같습니다.

앨라 배라

음순

아 발랄

발라 알라

알라 랩

라라 바

알라 발

그중에서 가장 작은 것은 "알라 발"입니다.

해결책에 관해서는- 접미사 배열 을 구성해야한다는 것을 알고 있으며 O (n)에서 그렇게 할 수 있다고 가정 해 봅시다. 내 질문은 여전히 ​​O (n)에서 가장 작은 회전을 어떻게 찾을 수 있습니까?입니다. (n = 문자열 길이)

나는이 문제에 매우 관심이 있고 여전히 해결책을 얻지 못합니다. 구체적인 구현이 아니라 개념과 문제 해결 방법에 더 관심이 있습니다.

참고 : 최소 회전은 영어 사전에서와 동일한 순서를 의미합니다. d는 w보다 앞에 있기 때문에 "dwor"는 "word"앞에 있습니다.

편집 : 접미사 배열 구성에는 O (N)이 필요합니다

마지막 편집 : 해결책을 찾은 것 같습니다 !!! 두 문자열을 병합하면 어떻게됩니까? 따라서 문자열이 "alabala"이면 새 문자열은 "alabalaalabala"이고 이제이 접미사 배열 (O (2n) = O (n))을 구성하고 첫 번째 접미사를 얻었습니까? 나는 이것이 옳을 것 같아요. 어떻게 생각해? 감사합니다!


"최소"를 어떻게 정의합니까? 사용 된 측정 항목은 무엇입니까 (어쩌면 분명하지만 전문가는 아닙니다)?
Giorgio

메모 주셔서 감사합니다! 나는 회전 순서 사전의 결과가 아니라 최소 회전 (최소 오프셋)이어야한다고 생각했습니다.
Giorgio

여전히 뭔가 빠졌습니다. 접미사 배열의 구성과 정렬이 복잡성에 포함되어 있습니까? 배열을 구성 하고 정렬하는 데 O (n) 이상이 필요하다고 생각 합니다.
Giorgio

원래 문자열을 두 번 반복한다는 아이디어가 훌륭하다고 생각합니다! 그런 다음 O (2n) = O (n)에 접미사 배열을 만들 수 있습니다. 그러나 최소값을 찾기 위해 정렬 할 필요가 없습니까? 이것은 O (n) 이상이 필요합니다.
Giorgio

@Giorgio 글쎄, 접미사 배열 자체는 이미 정렬 된 접미사를 보유합니다 . 그리고 또 다른 메모, 아마도 약간 주제가 아닐 수도 있습니다-정렬 된 객체에 대한 몇 가지 가정을 통해 o (n)에서도 정렬을 수행 할 수 있다는 것을 잊지 마십시오 (예 : 기수 정렬을 확인하십시오)
Tomy

답변:


5

길이가 N 인 문자열의 모든 회전을 구성하는 간단한 방법은 문자열을 자체와 연결하는 것입니다.

그런 다음이 2N 길이 문자열의 모든 N 길이 하위 문자열은 원래 문자열의 회전입니다.

그런 다음 O (N) 트리 구성을 사용하여 "사 전적으로 최소"하위 문자열을 찾습니다.


0

접미사 배열에 포함 된 정보가 O (n)에 도달하는 데 충분하지 않지만 O (n log n)에 도움이 될 수 있다고 확신합니다. 이 접미사 계열을 고려하십시오.

a
aba
abacaba
abacabadabacaba
abacabadabacabaeabacabadabacaba
...

이전 접미사 (예 : aba)를 가져 와서 아직 사용되지 않은 다음 문자를 추가 한 다음 이전 접미사를 다시 추가하여 다음 접미사를 구성합니다 (aba-> aba c aba).

이제 다음 문자열을 고려하십시오 (공백이 강조되도록 추가되었지만 문자열의 일부는 아님).

ad abacaba
bd abacaba
cd abacaba

이 세 문자열의 경우 접미사 배열의 시작은 다음과 같습니다.

a
aba
abacaba
(other suffixes)

익숙해 보이나요? 이 문자열은 물론이 접미사 배열을 만들도록 조정되었습니다. 이제 시작 문자 (a, b 또는 c)에 따라 '올바른'지수 (문제의 해결책)는 위 목록의 첫 번째, 두 번째 또는 세 번째 접미사입니다.

첫 글자 선택은 접미사 배열에 거의 영향을 미치지 않습니다. 특히 접미사 배열의 처음 세 접미사 순서에는 영향을 미치지 않습니다. 이것은 접미사 배열이 매우 유사하지만 '올바른'색인이 매우 다른 log n 문자열을 가지고 있음을 의미합니다.

나는 확실한 증거는 없지만, 어휘 순서에 대해 배열의 처음 3 개의 인덱스에 해당하는 회전을 비교하는 것 외에는 선택의 여지가 없다는 것을 강력하게 제안합니다. 이는 적어도 O (n log n) 시간 (대체 첫 문자의 수-우리의 경우 3-은 log n이므로 두 문자열을 비교하는 데 O (n) 시간이 걸립니다).

이것은 O (n) 알고리즘의 가능성을 배제하지 않습니다. 서 픽스 배열이이 러닝 타임을 달성하는 데 도움이된다는 의문이 있습니다.


0

가장 작은 회전은 접미사 배열의 일부 접미사로 시작하는 회전입니다. 접미어는 사전 식으로 정렬됩니다. 이것은 당신에게 큰 도약을 제공합니다 :

  • 접미사 k 로 시작하는 회전이 접미사 k +1로 시작하는 회전보다 작은 k 를 얻었 으면 완료된 것입니다 (처음부터 시작).
  • 당신은 "접미사로 시작하는 회전을 비교 한 작업을 수행 할 수 있습니다 K 접미사로 선발진보다 작은 K 서로 문자로 한 문자를 비교, 선택적 접미사의 길이를 비교하여 O (1)에서 일을."

편집 : "다른 문자가있는 한 문자"는 항상 같지는 않지만 하나 이상의 문자 일 수도 있지만 전체적으로 전체 검색 프로세스를 통해 n 문자 이상을 검사하지 않으므로 O (n)입니다.

짧은 증거 : 접미사 k +1이 접미사 k 보다 긴 경우에만 문자를 검사 하고 접미사 k +1이 접미사 k 보다 짧은 경우 해결책을 중지하고 발견합니다 (그러면 접미사 k 가 원하는 것을 알 수 있습니다). 따라서 접미사 순서가 길어질 때만 문자를 검사합니다. 초과 문자 만 검사하므로 n 개 이상의 문자를 검사 할 수 없습니다.

EDIT2 :이 알고리즘은 "접미사 배열에 두 개의 인접 접미사가 있고 이전이 다음보다 짧으면 이전이 후속의 접두사"라는 사실에 의존합니다. 이것이 사실이 아니라면 죄송합니다.

EDIT3 : 아니요, 보류하지 않습니다. "abaaa"에는 접미사 테이블 "a", "aa", "aaa", "abaaa", "baaa"가 있습니다. 그러나 아마도 이러한 생각은 궁극적으로 해결책으로 이어질 수 있습니다. 더 자세한 것은 더 정교해야합니다. 주된 질문은 적은 문자를 검사하여 위에서 언급 한 비교를 수행 할 수 있는지 여부입니다. 따라서 O (n)은 완전히 가능합니다. 나는 지금 어떻게 말할 수 없다.


0

문제:

사 전적으로 최소 원형 하위 문자열은 그러한 모든 회전 중에서 가장 낮은 사전 순을 갖는 스트링의 회전을 찾는 문제이다. 예를 들어, "bbaaccaadd"의 사 전적으로 최소 회전은 "aaccaaddbb"입니다.

해결책:

AO (n) 시간 알고리즘은 Jean Pierre Duval (1983)에 의해 제안되었습니다.

두 지표 감안 i하고 j, 듀발의 알고리즘은 길이의 문자열 세그먼트 비교 j - i에서 시작 i하고 j(불리는 "결투" ). 경우 index + j - i문자열의 길이보다 큰 경우, 세그먼트가 주위에 배치하여 형성된다.

예를 들어, s = "baabbaba", i = 5 및 j = 7을 고려하십시오. j-i = 2이므로 i = 5에서 시작하는 첫 번째 세그먼트는 "ab"입니다. j = 7에서 시작하는 두 번째 세그먼트는 줄 바꿈으로 구성되며 "ab"입니다. 위의 예에서와 같이 문자열이 사전 식으로 동일한 경우, i에서 시작하는 문자열을 i = 5로 선택합니다.

위 과정은 한 명의 당첨자가 될 때까지 반복됩니다. 입력 문자열의 길이가 홀수 인 경우 첫 번째 반복에서 비교하지 않고 마지막 문자가 승리합니다.

시간 복잡성 :

첫 번째 반복은 길이 1 (n / 2 비교) 각각의 n 개 문자열을 비교하고, 두 번째 반복은 i 번째 반복이 2 개의 문자열을 비교할 때까지 길이 2의 n / 2 문자열 (n / 2 비교) 등을 비교할 수 있습니다. 길이 n / 2 (n / 2 비교). 승자의 수는 매번 반으로 줄어들 기 때문에 재귀 트리의 높이는 log (n)이므로 O (n log (n)) 알고리즘을 제공합니다. 작은 n의 경우 이것은 대략 O (n)입니다.

첫 번째 반복에서는 n / 2 수상자, 두 번째 반복 n / 4 수상자 등을 저장해야하므로 공간 복잡도도 O (n)입니다. (Wikipedia는이 알고리즘이 일정한 공간을 사용한다고 주장합니다. 어떻게 이해하지 못합니다).

다음은 스칼라 구현입니다. 좋아하는 프로그래밍 언어로 자유롭게 변환하십시오.

def lexicographicallyMinRotation(s: String): String = {
 @tailrec
 def duel(winners: Seq[Int]): String = {
   if (winners.size == 1) s"${s.slice(winners.head, s.length)}${s.take(winners.head)}"
   else {
     val newWinners: Seq[Int] = winners
       .sliding(2, 2)
       .map {
         case Seq(x, y) =>
           val range = y - x
           Seq(x, y)
             .map { i =>
               val segment = if (s.isDefinedAt(i + range - 1)) s.slice(i, i + range)
               else s"${s.slice(i, s.length)}${s.take(s.length - i)}"
               (i, segment)
             }
             .reduce((a, b) => if (a._2 <= b._2) a else b)
             ._1
         case xs => xs.head
       }
       .toSeq
     duel(newWinners)
   }
 }

 duel(s.indices)
}

-1

O (N²)보다 더 좋은 것은 없습니다.

N 개의 정수 목록이 있으면 가장 작은 O (N) 비교를 선택할 수 있습니다.

여기에 N 크기의 N 문자열 목록이 있습니다 (비용이 들지 않으면 문자열은 시작 색인에 의해 완전히 결정됩니다). O (N) 비교에서 가장 작은 것을 선택할 수 있습니다. 그러나 각 비교는 O (N) 기본 연산입니다. 복잡성은 O (N²)입니다.

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