happy318
팽도리블로그
happy318
전체 방문자
오늘
어제
  • 전체글 (252)
    • 공부 (5)
      • Algorithm 정리 (0)
      • 논문리뷰 (1)
      • C++ (2)
      • Python (2)
      • Java (0)
      • Back-end (0)
      • Front-end (0)
      • Embedded (0)
    • 코딩테스트 (218)
      • Python 문제풀이 (100)
      • C++ 문제풀이 (108)
      • Python template (9)
      • C++ template (1)
    • 일상 (20)
      • 맛집 (13)
      • 쇼핑 (5)
      • 아무 일상 (2)
    • 게임 (9)
      • 메이플스토리 (9)

최근 글

인기 글

hELLO · Designed By 정상우.
happy318

팽도리블로그

코딩테스트/Python 문제풀이

[백준] 공통 부분 문자열

2022. 6. 28. 01:58

https://www.acmicpc.net/problem/5582

 

5582번: 공통 부분 문자열

두 문자열이 주어졌을 때, 두 문자열에 모두 포함된 가장 긴 공통 부분 문자열을 찾는 프로그램을 작성하시오. 어떤 문자열 s의 부분 문자열 t란, s에 t가 연속으로 나타나는 것을 말한다. 예를 들

www.acmicpc.net

lcs, lcp 문제로 흔히 불리우는 문제의 장르입니다. 

(dp로 해결)

(이 문제는 longest substring 문제로 잘 알려져있습니다.)

 

우선 문제부터 간단하게 요약하면,

두 string이 input으로 들어오면, 해당하는 두 string의 부분 string중 가장 길이가 긴 것의 문자열 길이를 return 해야합니다. 

 

<Solution>

간단한 그림을 통해 아이디어를 살펴봅시다. 

dp array를 search 하면서 각 가로축과 세로축의 문자가 같아지는 순간 왼쪽 사선방향칸의 number + 1을 해주면 됩니다. 

 

이것이 성립하는 이유는 간단합니다. 위 그림에서 dp[i][j] 칸이 의미하는 바가 s1의 0~i 번째 문자열와 s2의 0~j 번째 문자열의 접미사의 겹치는 길이이기 때문입니다.

예를 들면, 위의 그림에서 b와 b가 만나는 지점인 2를 봅시다. 이 경우는 ab, fghab의 접미사중 가장 긴 ab의 길이인 2가 들어오게 됩니다.

 

이처럼 dp 테이블을 구성해서 문제를 해결할 수 있습니다.

 

실제 구현은 아래와 같습니다.

import sys

s1 = sys.stdin.readline().rstrip()
s2 = sys.stdin.readline().rstrip()

dp_array = [[0] * (len(s2)+1) for _ in range(len(s1)+1)]

ans = 0
for i in range(1, len(s1) + 1):
    for j in range(1, len(s2) +1):
        if s1[i-1] == s2[j-1]:
            dp_array[i][j] = dp_array[i-1][j-1] + 1
            ans = max(ans, dp_array[i][j])
        else:
            continue
print(ans)

 

<참고할만한 것들>

- dp를 이용한 O(nm) time complexity로 해결하는법

https://www.geeksforgeeks.org/longest-common-substring-dp-29/

 

Longest Common Substring | DP-29 - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

+ 추가

https://www.acmicpc.net/problem/16908

 

16908번: 가장 긴 공통 부분 문자열

첫째 줄에 문자열의 개수 N(2 ≤ N ≤ 10)이 주어진다. 둘째 줄부터 N개의 줄에 문자열이 한 줄에 하나씩 주어진다. 문자열 하나의 길이는 100,000보다 작거나 같고, 알파벳 소문자로만 이루어져 있다

www.acmicpc.net

이 문제의 확장형인 16908을 해결하려 했으나 테스트 케이스들은 맞는것 같은데 현재는 메모리 초과로 돌아가지 않고 있습니다.

 

문자열의 갯수가 몇개든 상관없이 돌아갈 수 있도록 일단은 구현을 해두었는데 2<=N<=10이라 메모리를 덜쓰고 구현이 가능할 것 같습니다. 더불어서 5582번의 문제 상황에서도 241mb정도를 사용하는데 당연히 메모리 초과가 날 것 같습니다. 

 

추후에 해결하면 다시 블로그에 포스팅하도록 하겠습니다. (찾아본 결과 dp말고 다른 알고리즘이나 다른 언어를 써야 할수도 있다 싶습니다.)

https://www.geeksforgeeks.org/suffix-tree-application-5-longest-common-substring-2/

 

Suffix Tree Application 5 - Longest Common Substring - GeeksforGeeks

Here we are implementing code to find Longest Common Substring using Suffix Tree. A Suffix Tree Application where we build a generalized suffix tree.

www.geeksforgeeks.org

 

(위의 dp알고리즘을 N개의 문자열로 확장한 코드)

import sys
import itertools
import copy
n = int(sys.stdin.readline().rstrip())

string_list = [sys.stdin.readline().rstrip() for _ in range(n)]

dp_array = [0] * (len(string_list[-1])+1)
idx_list = []

for s in string_list[-2::-1]:
    dp_array = [copy.deepcopy(dp_array) for _ in range(len(s)+1)]
for s in string_list:
    idx_list.append(list(range(len(s))))

for_loop = [p for p in itertools.product(*idx_list)]

def get_element(table, index):
    for ind, e_ in enumerate(index):
        if ind == 0:
            e__ = table[e_]
        else:
            e__ = e__[e_]
    return e__
def modify_element(table, index, num):
    len_idx = len(index)
    for ind, e_ in enumerate(index):
        if ind == 0:
            e__ = table[e_]
        else:
            if ind == len_idx-1:
                e__[e_] = num
            else: 
                e__ = e__[e_]

ans = 0

for e in for_loop:
    # check if all elements are same
    flag = 0
    tmp = string_list[0][e[0]]
    for i in range(1,len(e)):
        if string_list[i][e[i]] != tmp:
            flag = 1
            break
        else:
            continue
    # if same
    if flag == 0:
        a = get_element(dp_array, e)
        modify_element(dp_array, list(map(lambda x: x+1, e)), a+1)
        ans = max(ans, a+1)

    # not same
    else:
        continue
print(ans)

 

반응형

'코딩테스트 > Python 문제풀이' 카테고리의 다른 글

[백준] 후위 표기식  (0) 2022.06.28
[백준] 최소비용 구하기  (0) 2022.06.28
[백준] 문자열 폭발  (0) 2022.06.26
[백준] N과 M (2)  (0) 2022.06.25
[백준] 2048 (Easy)  (0) 2022.06.25
    '코딩테스트/Python 문제풀이' 카테고리의 다른 글
    • [백준] 후위 표기식
    • [백준] 최소비용 구하기
    • [백준] 문자열 폭발
    • [백준] N과 M (2)
    happy318
    happy318

    티스토리툴바