[본 문제는 정확성과 효율성 테스트 각각 점수가 있는 문제입니다.]
친구들로부터 천재 프로그래머로 불리는 "프로도"는 음악을 하는 친구로부터 자신이 좋아하는 노래 가사에 사용된 단어들 중에 특정 키워드가 몇 개 포함되어 있는지 궁금하니 프로그램으로 개발해 달라는 제안을 받았습니다.그 제안 사항 중, 키워드는 와일드카드 문자중 하나인 '?'가 포함된 패턴 형태의 문자열을 뜻합니다. 와일드카드 문자인 '?'는 글자 하나를 의미하며, 어떤 문자에도 매치된다고 가정합니다. 예를 들어 "fro??"
는 "frodo"
, "front"
, "frost"
등에 매치되지만 "frame"
, "frozen"
에는 매치되지 않습니다.
가사에 사용된 모든 단어들이 담긴 배열 words
와 찾고자 하는 키워드가 담긴 배열 queries
가 주어질 때, 각 키워드 별로 매치된 단어가 몇 개인지 순서대로 배열에 담아 반환하도록 solution
함수를 완성해 주세요.
words
의 길이(가사 단어의 개수)는 2 이상 100,000 이하입니다.words
에는 하나로만 제공됩니다.queries
의 길이(검색 키워드 개수)는 2 이상 100,000 이하입니다.'?'
로만 구성되어 있으며, 특수문자나 숫자는 포함하지 않는 것으로 가정합니다.'?'
가 하나 이상 포함돼 있으며, '?'
는 각 검색 키워드의 접두사 아니면 접미사 중 하나로만 주어집니다."??odo"
, "fro??"
, "?????"
는 가능한 키워드입니다."frodo"
('?'
가 없음), "fr?do"
('?'
가 중간에 있음), "?ro??"
('?'
가 양쪽에 있음)는 불가능한 키워드입니다.words | queries | result |
---|---|---|
["frodo", "front", "frost", "frozen", "frame", "kakao"] | ["fro??", "????o", "fr???", "fro???", "pro?"] | [3, 2, 4, 1, 0] |
"fro??"
는 "frodo"
, "front"
, "frost"
에 매치되므로 3입니다."????o"
는 "frodo"
, "kakao"
에 매치되므로 2입니다."fr???"
는 "frodo"
, "front"
, "frost"
, "frame"
에 매치되므로 4입니다."fro???"
는 "frozen"
에 매치되므로 1입니다."pro?"
는 매치되는 가사 단어가 없으므로 0 입니다.import re
def solution(words, queries):
answer = []
for query in queries:
cnt = 0
q_len = len(query)
query = query.replace('?', '.')
query = re.compile(query)
for word in words:
if len(word) != q_len:
continue
if query.match(word) != None:
cnt += 1
answer.append(cnt)
return answer
def solution(words, queries):
head, head_rev = {}, {}
wc = []
def add(head, word):
node = head
for w in word:
if w not in node:
node[w] = {}
node = node[w]
if 'len' not in node:
node['len'] = [len_word]
else:
node['len'].append(len_word)
node['end'] = True
for word in words:
len_word = len(word)
add(head, word)
add(head_rev, word[::-1])
wc.append(len_word)
def search(head, querie):
count = 0
node = head
for q in querie:
if q == '?':
return node['len'].count(len_qu)
elif q not in node:
break
node = node[q]
return count
li = []
for querie in queries:
len_qu = len(querie)
if querie[0] == '?':
if querie[-1] == '?':
li.append(wc.count(len_qu))
else:
li.append(search(head_rev, querie[::-1]))
else:
li.append(search(head, querie))
return li
return node['len'].count(len_qu)
해당 노드까지 일치한 단어들 중 query와 길이가 동일한 단어들을 카운트하여 반환def solution(words, queries):
head, head_rev = {}, {}
wc = []
def add(head, word):
node = head
for w in word:
if w not in node:
node[w] = {}
node = node[w]
if 'len' not in node:
node['len'] = [len_word]
else:
node['len'].append(len_word)
node['end'] = True
for word in words:
len_word = len(word)
add(head, word)
add(head_rev, word[::-1])
wc.append(len_word)
def search(head, querie):
count = 0
node = head
for q in querie:
if q == '?':
return node['len'].count(len_qu)
elif q not in node:
break
node = node[q]
return count
li = []
for querie in queries:
len_qu = len(querie)
if querie[0] == '?':
if querie[-1] == '?':
li.append(wc.count(len_qu))
else:
li.append(search(head_rev, querie[::-1]))
else:
li.append(search(head, querie))
return li
입력되는 문자열을 tree 형식으로 만들어 빠르게 문자열 검색이 가능한 자료 구조
보통 문자열이 존재하는지 확인하기 위해서는 O(n) 시간 소요
Trie 알고리즘 사용하면 O(m) 소요 (m은 문자열의 길이)
문자열을 검색하는 문제에서 입력되는 문자열이 많을 경우 자주 사용
노드를 이용한 tree 형태로 이루어져 있음
문자열의 끝을 알리는 flag가 존재
key: 값으로 입력될 문자
data: 문자열의 종료를 알리는 flag
children: 자식 노드 저장
class Node(object):
def __init__(self, key, data=None):
self.key = key
self.data = data
self.children = {}
class Trie:
def __init__(self):
self.head = Node(None)
def insert(self, string):
current_node = self.head
for char in string:
if char not in current_node.children:
current_node.children[char] = Node(char)
current_node = current_node.children[char]
current_node.data = string
def search(self, string):
current_node = self.head
for char in string:
if char in current_node.children:
current_node = current_node.children[char]
else:
return False
if current_node.data:
return True
else:
return False
def starts_with(self, prefix):
current_node = self.head
words = []
for p in prefix:
if p in current_node.children:
current_node = current_node.children[p]
else:
return None
current_node = [current_node]
next_node = []
while True:
for node in current_node:
if node.data:
words.append(node.data)
next_node.extend(list(node.children.values()))
if len(next_node) != 0:
current_node = next_node
next_node = []
else:
break
return words