라떼는말이야

[solved.ac 실버3] 14426_접두사 찾기 (파이썬, 문자열) 본문

알고리즘

[solved.ac 실버3] 14426_접두사 찾기 (파이썬, 문자열)

MangBaam 2022. 6. 29. 23:59
반응형

밑의 사진을 클릭하면 문제 링크로 이동합니다

제한 사항

문제

문자열 S의 접두사란 S의 가장 앞에서부터 부분 문자열을 의미한다. 예를 들어, S = "codeplus"의 접두사는 "code", "co", "codepl", "codeplus"가 있고, "plus", "s", "cude", "crud"는 접두사가 아니다.

총 N개의 문자열로 이루어진 집합 S가 주어진다.

입력으로 주어지는 M개의 문자열 중에서 집합 S에 포함되어 있는 문자열 중 적어도 하나의 접두사인 것의 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 문자열의 개수 N과 M (1 ≤ N ≤ 10,000, 1 ≤ M ≤ 10,000)이 주어진다.

다음 N개의 줄에는 집합 S에 포함되어 있는 문자열이 주어진다.

다음 M개의 줄에는 검사해야 하는 문자열이 주어진다.

입력으로 주어지는 문자열은 알파벳 소문자로만 이루어져 있으며, 길이는 500을 넘지 않는다. 집합 S에 같은 문자열이 여러 번 주어지는 경우는 없다. 

출력

첫째 줄에 M개의 문자열 중에 총 몇 개가 포함되어 있는 문자열 중 적어도 하나의 접두사인지 출력한다.

예제


나의 풀이

파이썬에는 startswith라는 메서드가 있다. A.startswith(B) 를 하면 A 문자열이 B 문자열로 시작하는지 알 수 있다.

일반적인 풀이

n, m = map(int, input().split())
words = [input() for _ in range(n)]
test = [input() for _ in range(m)]
answer = 0
for i in range(m):
    for j in range(n):
        if words[j].startswith(test[i]):
            answer += 1
            break
print(answer)

가장 쉽게 생각할 수 있는 풀이는 위와 같다. 단순히 문자열을 순회하며 일일이 비교해보다가 특정 문자열로 시작하는 경우를 발견하면 answer을 1 증가시키고 해당 반복문은 빠져나간다. (이미 찾았으니까 남은 단어들을 더 확인할 필요가 없다)

빠른 풀이

import string

n, m = map(int, input().split())
words = {x: [] for x in string.ascii_lowercase}
for _ in range(n):
    word = input()
    words[word[0]].append(word)
test = sorted([input() for _ in range(m)])
answer = 0
for i in range(m):
    for word in words[test[i][0]]:
        if word.startswith(test[i]):
            answer += 1
            break
print(answer)

빠른 풀이는 dict 자료구조를 사용한 해싱으로 할 수 있다.

string.ascii_lowercase에는 abc...xyz 의 알파벳 소문자가 들어있다. 이것을 key로 하고 list를 value로 하는 dict를 만든다.

이렇게 하면 test의 어떤 단어를 검사하는데 words의 모든 단어를 검사하는 것이 아니라 words에서 해당 알파벳으로 시작하는 단어만 검사할 수 있게 된다.

N과 M이 최대 10,000 이고, 모든 단어가 접두사가 아니라면 100,000,000 만큼의 시간이 소요될 것이다. 1초에 약 1억 번의 연산을 할 수 있다고 했을 때 최악의 경우 1초가 걸릴 것이고, 이 문제의 시간 제한인 1초에 걸릴 수도 있는 것이다.

하지만 해싱을 하게 되면 모든 단어가 특정 알파벳으로 시작하는 것이 아닌 이상 훨씬 더 짧은 시간이 소요될 것이다.

일반적인 풀이 결과
빠른 풀이 결과

 

반응형
Comments