[programmers] 가사찾기_binary search, trie
Date:
블럭 이동하기
내 풀이
- 방식 : binary search
- 물음표를 제외한 문자열 binary search로 찾기
- python에서는 여러 문자열에 대한 비교연산사 가능함
- 같은 길이에 대한 sorting은 한번만 할 수 있도록 dp로 구현
📰code
from collections import defaultdict
def solution(words, queries):
answer = []
words_dict = defaultdict(list)
words_dict_reverse = defaultdict(list)
# word 길이에 따른 hash table 구성(정방향, 반대방향)
for word in words:
words_dict[len(word)].append(word)
words_dict_reverse[len(word)].append(word[::-1])
def binary_search(arr,i,q,l,r,d):
mid = int((l+r)/2)
if r <= l:
return l
elif arr[mid][:i]<q[:i]:
return binary_search(arr,i,q,mid+1,r,d)
elif arr[mid][:i]>q[:i]:
return binary_search(arr,i,q,l,mid,d)
else : # arr[mid]==x
if d == 'left':
return binary_search(arr,i,q,l,mid,d)
else : # right
return binary_search(arr,i,q,mid+1,r,d)
def find_p(words_list,search_dir,q):
length = len(words_list[0])
# 물음표 위치 확인
for i in range(length):
if q[i] =='?': break
left, right = 0,len(words_list)
# 물음표를 제외한 문자열 만큼 binary search로 좌표확인
left = binary_search(words_list,i,q,left, right, 'left')
right = binary_search(words_list,i,q,left, right, 'right')
return right - left
# wordlist 정렬 한번만 하도록 dp 구성
dp_rev = [0]*100001
dp = [0]*100001
for q in queries:
q_l=len(q)
# 해당 길이에 대한 단어 없음
if words_dict[q_l] ==[]:
answer.append(0)
# '?'로 시작할 경우 reverse로 찾기
elif q.startswith('?'):
search_dir = 'back'
if dp_rev[q_l] ==0 :
words_dict_reverse[q_l] = sorted(words_dict_reverse[q_l])
dp_rev[q_l]=1
words_list = words_dict_reverse[q_l]
answer.append(find_p(words_list,search_dir,q[::-1]))
# '?'로 끝날 경우 정방향으로 찾기
else :
search_dir = 'front'
if dp[q_l] == 0 :
words_dict[q_l] = sorted(words_dict[q_l])
dp[q_l]=1
words_list = words_dict[q_l]
answer.append(find_p(words_list,search_dir,q))
return answer
1트 code _ NG
📰code
from collections import defaultdict
def solution(words, queries):
answer = []
words_dict = defaultdict(list)
for word in words:
words_dict[len(word)].append(word)
ans_memo = defaultdict(list)
def binary_search(arr,i,q,l,r,d):
mid = int((l+r)/2)
if r <= l:
return l
elif ord(arr[mid][i])<ord(q[i]): # 파이썬에서는 ord 사용안해도 여러 문자열 비교 가능
return binary_search(arr,i,q,mid+1,r,d)
elif ord(arr[mid][i])>ord(q[i]):
return binary_search(arr,i,q,l,mid,d)
else : # arr[mid]==x
if d == 'left':
return binary_search(arr,i,q,l,mid,d)
else : # right
return binary_search(arr,i,q,mid+1,r,d)
def find_p(words_list,search_dir,q):
length = len(words_list[0])
if search_dir == 'front':
for i in range(length):
left, right = 0,len(words_list)
if q[i] =='?':
return right - left
temp_list = sorted(words_list[left:right], key = lambda x:x[i]) #지속적으로 정렬이 필요함.. 이 부분 개선 필요
left = binary_search(temp_list,i,q,left, right, 'left')
right = binary_search(temp_list,i,q,left, right, 'right')
words_list = temp_list[left:right]
else : # search_dir == 'front':
for i in range(length-1,-1,-1):
left, right = 0,len(words_list)
if q[i] =='?':
return right - left
temp_list = sorted(words_list[left:right], key = lambda x:x[i])
left = binary_search(temp_list,i,q,left, right, 'left')
right = binary_search(temp_list,i,q,left, right, 'right')
words_list = temp_list[left:right]
for q in queries:
if words_dict[len(q)] ==[]:
answer.append(0)
elif q.startswith('?'):
search_dir = 'back'
words_list = words_dict[len(q)]
answer.append(find_p(words_list,search_dir,q))
else :
search_dir = 'front'
words_list = words_dict[len(q)]
answer.append(find_p(words_list,search_dir,q))
return answer
다른 사람 풀이_Trie
📰code
class Node:
def __init__(self, data):
self.data = data
self.count = 0
self.child = {} # dictionary 형태로 Tree 생성
class Trie:
def __init__(self):
self.head = Node(None)
def insert(self, string):
cur = self.head
cur.count += 1
for c in string:
if c not in cur.child:
cur.child[c] = Node(c) # 새로운 Node에 data, count, child로 업데이트
cur = cur.child[c]
cur.count += 1
def count(self, prefix):
cur = self.head
for c in prefix:
if c not in cur.child:
return 0
cur = cur.child[c]
return cur.count
def solution(words, queries):
answer = []
tries = create_trie(words)
reversed_tries = create_trie(words, is_reversed = True)
for query in queries:
answer.append(count_matched_word(tries, reversed_tries, query))
return answer
def create_trie(words, is_reversed = False):
trie_dic = {i: Trie() for i in range(1, 10001)}
for word in words:
if is_reversed:
word = word[::-1]
trie_dic[len(word)].insert(word)
return trie_dic
def count_matched_word(tries, reversed_tries, query):
no_mark_query = query.replace('?', '')
if query[0] == '?':
return reversed_tries[len(query)].count(no_mark_query[::-1])
else:
return tries[len(query)].count(no_mark_query)
💡 수정 필요한 내용은 댓글이나 메일로 알려주시면 감사하겠습니다!💡
댓글