• Feed
  • Explore
  • Ranking
/
/
    백준

    백준 6550번) 부분 문자열 (Python, Greedy)

    밤
    밤톨이형아
    2026.03.04
    ·
    6 min read

    8838

    백준 6550번 - 부분 문자열 (Python)

    문제 요약

    두 문자열 s와 t가 주어졌을 때, s가 t의 부분 문자열(subsequence)인지 판단하는 문제다.

    여기서 "부분 문자열"이란, t에서 몇 개의 문자를 제거하고 순서를 바꾸지 않고 합쳤을 때 s가 되는 경우를 말한다. 입력은 여러 테스트 케이스로 이루어져 있고, EOF까지 반복해서 읽어야 한다.


    풀이 접근

    핵심 아이디어는 간단하다. s의 각 문자를 순서대로 t에서 찾되, 이전에 매칭된 위치 이후부터 탐색하는 것이다. s의 모든 문자를 순서대로 t 안에서 찾을 수 있다면 Yes, 하나라도 못 찾으면 No를 출력한다.

    내 코드에서는 매칭에 성공할 때마다 t = t[j+1:]로 t를 슬라이싱해서, 다음 탐색의 시작 위치를 자연스럽게 앞으로 밀어주는 방식을 사용했다.


    시간 복잡도

    s의 길이를 N, t의 길이를 M이라 하자.

    외부 반복문은 s의 각 문자에 대해 최대 N번, 내부 반복문은 t를 순회하면서 매칭을 찾는다. 매칭에 성공하면 t를 슬라이싱하므로 이후 탐색 범위가 줄어든다. 결국 t의 각 문자는 전체 과정에서 최대 한 번만 비교되기 때문에 비교 자체의 총 횟수는 O(M)이다.

    다만, t = t[j+1:] 슬라이싱이 매번 새로운 문자열을 생성하므로 이 부분에서 추가 비용이 발생한다. 슬라이싱은 남은 t의 길이만큼 복사하므로, 최악의 경우 총 슬라이싱 비용은 O(M × N)까지 갈 수 있다. (예: s의 모든 문자가 t앞쪽에 몰려 있는 경우)

    문제 제한이 s, t 길이 모두 10만 이하이므로 통과에는 문제없지만, 만약 효율을 극대화하고 싶다면 슬라이싱 대신 인덱스 변수(투 포인터)를 사용하는 것이 더 깔끔하다.


    로직 순서별 해설

    1. 입력 처리 및 EOF 대응

    while True:
        try:
            s, t = sys.stdin.readline().split()
    

    테스트 케이스 수가 정해져 있지 않으므로 while True로 무한 루프를 돌리고, try-except로 EOF를 잡아 종료한다. sys.stdin.readline()을 쓴 이유는 input()보다 입력 속도가 빠르기 때문이다.

    2. s의 각 문자를 t에서 순서대로 탐색

    check_1 = False
    for i in range(len(s)):
        check_2 = False
        for j in range(len(t)):
            if s[i] == t[j]:
                t = t[j+1:]
                check_2 = True
                break
    

    s[i]를 현재 t에서 앞에서부터 찾는다. 찾으면 t를 해당 위치 다음부터 잘라서 갱신하고, check_2 = True로 매칭 성공을 표시한 뒤 내부 루프를 탈출한다.

    슬라이싱 t = t[j+1:]이 핵심인데, 이렇게 하면 다음 s[i+1]을 탐색할 때 이미 사용한 부분은 자연스럽게 제외된다.

    3. 매칭 실패 시 즉시 No 출력

        if check_2 == False:
            print("No")
            check_1 = True
            break
    

    t 전체를 다 돌았는데도 s[i]와 일치하는 문자가 없으면 check_2가 False인 채로 남는다. 이 경우 s는 t의 부분 문자열이 될 수 없으므로 No를 출력하고 외부 루프도 탈출한다.

    4. 모든 문자 매칭 성공 시 Yes 출력

    if check_1 == False:
        print("Yes")
    

    외부 루프가 break 없이 정상 종료됐다면 check_1은 여전히 False다. 이는 s의 모든 문자가 t에서 순서대로 매칭됐다는 뜻이므로 Yes를 출력한다.

    5. 예외 처리로 종료

        except:
            break
    

    입력이 끝나면 readline()이 빈 문자열을 반환하고, .split()이 빈 리스트를 반환해서 언패킹에서 ValueError가 발생한다. 이걸 except로 잡아서 루프를 종료한다.


    전체 코드

    import os, sys
    
    while True:
        try:
            s, t = sys.stdin.readline().split()
            check_1 = False
            for i in range(len(s)):
                check_2 = False
                for j in range(len(t)):
                    if s[i] == t[j]:
                        t = t[j+1:]
                        check_2 = True
                        break
                if check_2 == False:
                    print("No")
                    check_1 = True
                    break
            if check_1 == False:
                print("Yes")
        except:
            break
    






    - 컬렉션 아티클