그냥 하는 노트와 메모장

[Dynamic programming/ Recursion] n번째 문자열에서 k번째 문자 찾아가기 튜토리얼 본문

Algorithms

[Dynamic programming/ Recursion] n번째 문자열에서 k번째 문자 찾아가기 튜토리얼

coloredrabbit 2019. 5. 24. 16:33

* n번째 문자열에서 k번째 문자 찾아가기 튜토리얼

  이따금씩 n번째 문자열에 대해 n-1번째 또는 그 이전의 문자열과의 관계가 주어지고, n번째 문자열의 k번째 문자를 출력하라는 문제가 등장합니다.

가령

  1번째 문자열 = "ffx"

  n번째 문자열 = "abcde" + n-1번째 문자열 + "fghijk" + n-1번째 문자열

처럼 점화식이 있는 상태에서 n번째 문자열의 k번째 문자를 출력하라는 겁니다.


  보통 이런 문제는 실제 n번째 문자열을 직접 구성해서 거기서 k번째를 가져오도록 못하게 메모리 또는 시간제한을 둡니다. 즉, 문제를 접근했을 때 직관적으로 떠오르는 풀이는 틀리게 문제를 구성한다는 거죠. 따라서 문자열을 빌드업하며 계산하는 방식은 사용할 수 없습니다.



문제)

베이스 :  = "abc"

점화식 :  = "fx"++"."+


  1. n번째 문자열()의 길이를 먼저 예측해보자!

    따라서 똑똑하게 k번째 문자열을 찾아갈 수 있어야 합니다. 점화식에 등장하는 구조를 보면 이전 상태를 이용하는 것을 관찰해봅시다. n번째 문자열()의 길이를 L[n]이라고 하면 L[n]은 점화식을 통해 구할 수 있습니다.

    L[n] = (n번째 이전의 문자열 길이의 합) + 기존 구성 문자열 길이

    문제의 경우 길이 점화식은 아래와 같습니다.

    L[n] = 2*L[n-1] + 3

    문자열 자체의 점화식을 도출해낼 수 있다면 당연히 그 길이에 대한 점화식도 구할 수 있습니다.


  2. 구간을 나눠서, k번째가 어디 구간에 속하는지 확인하자!

    길이 점화식을 다시금 정리해봅시다. 순서대로 나열해보면

    L[n] = 2 + L[n-1] + 1 + L[n-1]이 됩니다.

    그럼 여기서 k번째를 찾는다고 하면 앞에서부터 탐색해 나가면 됩니다. k번째가 2번째 이하라면 "fx"에 속할테고, 2번째 초과 && 2 + L[n-1]번째 이하라면 L[n-1]번째 문자열에 속한 문자가 됩니다. 이때 에서 k번째를 다시 예측하는 구조를 가지게 되죠. 이런 방식을 찾을 때까지 적용시켜 나갑니다. 


  슈도 코드는 다음과 같습니다.

function find(n, k)
  if n = 0
    return S0[k]
  if k <= 2
    return "fx"[k]
  else if k <= 2 + L[n-1]
    return find(n-1, k-2)  //Sn-1에 대해 다시 예측
  else if k <= 2 + L[n-1] + 1
    return '.'
  else
    return find(n-1,k-2-L[n-1]-1)  //Sn-1에 대해 다시 예측

 

  핵심은 k번째 구간이 '어디에 속하는 지를 확인하여 현재 어느 위치에 있을지 예측'하는 것이죠.

  위의 문제의 경우 4개의 구간이 있으면 1번째 구간은 "fx", 2번째는 , 3번째는 ".", 4번째는 으로 구간을 나눌 수 있습니다. 따라서 구간별로 길이가 "정해져 있음"에 우리는 k번째가 쉽게 어느 구간에 있을지 계산 가능하죠.


  * 첨언

  위의 방식은 꼬리 재귀(tail recursion)이기 때문에 대부분 반복문으로 대체 가능합니다. 구현은 재귀로 해도 좋고, 반복문으로 순차 접근해도 좋습니다. 단, 재귀는 스택 메모리를 잡아먹기 때문에 n의 범위가 크면 클수록(하위 문자열에 대해 다시 예측하는 모델이기에) 그만큼 메모리를 가진다는 것을 알아두세요.




  자, 문제에 적용해봅시다.

  풀이 보시기 전에 위 방식으로 한 번 접근해보세요.


1. 드래곤 커브 (https://algospot.com/judge/problem/read/DRAGON)


2. Nephren gives a riddle (https://codeforces.com/contest/896/problem/A)


3. Kth Character (https://www.codechef.com/problems/KCHAR), Googol String (https://www.acmicpc.net/problem/12075)


4. XYZ 문자열(https://www.acmicpc.net/problem/1663)


Comments