본문 바로가기

Toy Problem

LPS : Longest Prefix which is also Suffix

문제 :

  • 문자열을 입력 받아 다음의 조건을 만족하는 LPS를 찾아 그 길이를 리턴한다.

 

조건:

  • non-overlapping. 즉, 접두어와 접미어는 서로 겹치는 부분이 없어야 한다.

 

참고:

  • prefix(접두어)는 문자열의 첫 인덱스부터 시작하는 모든 부분 문자열을 의미한다.
  • suffix(접미어)는 문자열의 마지막 인덱스부터 시작하는 모든 부분 문자열을 의미한다.

 


pseudocode

 

1. prefix이자 suffix인 것 중 가장 긴 부분 문자열을 구하면서 서로 겹치지 않으려면 

      - prefix는 최대 문자열 길이의 1/2지점까지이며

      - suffix는 문자열 길이의 1/2 지점부터 끝까지가 되어야 한다. (str의 길이가 홀수인 경우 prefix가 더 길다.)

  abaab를 예로 들면 prefix === { a, ab, aba}, prefix === {b, ab} 가 된다.

 

2. if(str[leftIdx] === str[rightIdx]) { 동시에 인덱스를 증가시킨다.}

    : 같은 문자를 찾아서 다음 문자도 일치하는지 확인하기 위해 동시에 인덱스를 증가시킨다.

 

3. if(str[leftIdx] !== str[rightIdx]) && if(str[leftIdx] ===0) { rightIdx를 증가시킨다.}

   : 아직 일치하는 것이 없는 경우 rightIdx만 증가시켜서 그 suffix의 두 번째 혹은 세 번째 등 다른 문자는 일치하는지 알아본다.

 

4. if(str[leftIdx] !== str[rightIdx]) && if(str[leftIdx] !==0) { leftIdx를 감소시킨다.}

   : 일치하는 문자들이 있다가 불일치를 만난 경우, leftIdx를 감소시켜서 해당 rightInx와 일치하는지 알아본다.

    *이 부분은 aaabbcaaaaab를 예제로 마지막에 다시 정리해보려고 한다.

 

5. 1~4까지를 while문에 넣어서 rightIdx가 str의 길이보다 작을 때까지만 탐색하도록 한다.

 

6. while문을 나오면 leftIdx를 반환한다.

 

 

 


코드 구현

const lps = function(str) {
  if(str.length < 2) return 0;
  
  let leftIdx = 0;
  let rightIdx = Math.ceil(str.length/2);
  
  while(rightIdx < str.length){
    if(str[leftIdx] === str[rightIdx]){
      leftIdx++;
      rightIdx++;
    }else if(str[leftIdx] === 0){
      rightIdx++;
    }else{
      leftIdx--;
    }
  }
  return leftIdx;
}

 

 

예제 1 : lps('abaab')

str : abaab

idx : 01234

prefix는 str[2]까지가 될 것이고 suffix는 str[3]부터 끝까지가 된다.

 

1. str[0]과 str[3]는 a로 같다. leftIdx++, rightIdx++

2. str[1]과 str[4]은 b로 같다. leftIdx++, rightIdx++

3. str[2]와 str[5]를 비교하려는데 rightIdx가 str.length와 같아졌으므로 while문을 나온다.

4. leftIdx인 2를 반환한다.

 

 

 

예제 2 : lps('aaabbcaaaaab')

str :  aaabbc aaaa  a b

idx : 012345 67891011

 

1. str[0]과 str[6]은 a로 일치하므로 인덱스를 둘 다 증가시킨다.

2. str[1]과 str[7]은 a로 일치하므로 인덱스를 둘 다 증가시킨다.

3. str[2]와 str[8]은 a로 일치하므로 인덱스를 둘 다 증가시킨다.

4. str[3]과 str[9]는 각각 b와 a로 일치하지 않으므로 leftIdx--한다.

5. str[2]와 str[9]는 a로 일치하므로 인덱스를 둘 다 증가시킨다.

6. str[3]와 str[10]은 각각 b와 a로 일치하지 않으므로 leftIdx--한다.

7. str[2]와 str[10]은 a로 일치하므로 인덱스를 둘 다 증가시킨다.

8. str[3]과 str[11]에서 rightIdx가 str.length보다 작지 않으므로 while문을 나간다.

9. leftIdx를 리턴하면 3이 반환된다.

 

불일치가 발생했더라도 prefix든 suffix든 위치만 조정하면 서로 같아질 수 있으므로

prefix의 위치를 조정해서 str의 길이까지 모두 탐색해보는 것이다.

 

리턴하는 leftIdx의 값은 일치하는 부분 문자열의 길이가 되기 때문에

leftIdx--의 의미는 결국 일치하지 않는 부분이 발생했을 때 그 길이를 차감하는 역할을 하게 된다고 이해하면 쉬울 것 같다.

'Toy Problem' 카테고리의 다른 글

Balanced Brackets  (0) 2021.01.04
Quick Sort  (0) 2020.12.27
Bubble Sort  (0) 2020.11.19