Assignment 3
이제까지 혼자만의 힘으로 풀어 굉장히 많은 시간을 소요했었는데 앞으로는 참고를 하며 이해를 하고 빠르게 넘어가야 할 것같다. 목표한 바보다 일정이 늦어졌기에.
1번 문제는 Phone book을 다루는 문제이다.
Input format :
N (number of queries)
queries (type number [name])
Output format :
results of each find query
첫번째 예시를 보면 처음에 등장하는 정수인 12가 12개의 query를 받을 준비가 됨을 알려주며 이후 add, find, del 의 명령의 동작에 맞게 작동한다. 그리고 find 명령마다 출력을 내보내준다.
기본코드이며 Query 클래스를 통해 입력받은 쿼리의 요소들을 분리하여 처리가 가능하고 read_queries, write_responses를 통해 입력을 받고 출력할 것들을 반환하게 된다. 마지막인 process_queries를 direct addressing을 통해 최적화를 진행해야 한다.
제약조건에 명시된 것처럼 contacts를 10^7으로 고정시켜놓고 이후 index를 통해 접근하여 바로 연산을 하는 것이 for문을 통해 작업하는 것보다 훨씬 빠를 것이다.
2번째는 chaining하는 문제이며 수식과 함께 미리 상수를 주었다.
p = 1 000 000 007, x = 263
Input format :
m (the number of buckets)
N (the number of queries)
queries
Output format :
result of find/check queries
이번에도 예시를 보면 쉽게 이해가능한데 첫번째 예시를 보면 받은 문자들에 대해 ASCII코드로 변환하고 이를 x^i과 연산 후 p로 modulo연산을 한 결과에 m으로 modulo한 값을 가지고 chaining을 한 것을 볼 수 있다. 이후에는 find/check에 대한 결과값들을 보내주게 된다.
추가적인 예시들까지 보고 overflow를 조심하라는 지시문도 확인하였다.
check일 경우에는 해당 ind에 해당하는 chain을 출력하도록 하고 이외의 경우엔 find, add, del type에 따라 연산을 진행해 주도록하면 될 것이다.
3번째 문제는 hash substring에 해당하는 find pattern in text에 관한 문제이다. Rabin-Karp 알고리즘을 활용해 해결하라는 지시가 있다.
Input format :
P (pattern)
T (text)
Output format :
position (all the occurrences of P in T, ascending order)
첫번째 예시를 보자면 P = aba, T = abacaba이므로 해당 결과는 0 4가 나올 것이다.
기초 코드상으로는 기본적인 기능으로 구현이 되어있고 양이 방대해질수록 연산시간이 더 많이 걸리게 된다.
hash_func에서는 chaining을 위한 연산값에 대한 수식이 들어가며 precompute_hashes에서는 hash value로 대응하는 역할을 한다. get_occurrences에서는 hash value를 먼저 비교 후 동일 값에 대해서만 다시 확인하여 반환해주는 순서로 구성되어 있다.
아래 출처에 있는 글을 참고하였으며 굉장히 깔끔하게 정리되어 있는 것을 보고 감탄하였다.
출처 : https://medium.com/@ltanphat/course-2-data-structure-part-3-hash-11ccf163cb09
이제까지 혼자만의 힘으로 풀어 굉장히 많은 시간을 소요했었는데 앞으로는 참고를 하며 이해를 하고 빠르게 넘어가야 할 것같다. 목표한 바보다 일정이 늦어졌기에.
1번 문제는 Phone book을 다루는 문제이다.
Input format :
N (number of queries)
queries (type number [name])
Output format :
results of each find query
첫번째 예시를 보면 처음에 등장하는 정수인 12가 12개의 query를 받을 준비가 됨을 알려주며 이후 add, find, del 의 명령의 동작에 맞게 작동한다. 그리고 find 명령마다 출력을 내보내준다.
# python3 class Query: def __init__(self, query): self.type = query[0] self.number = int(query[1]) if self.type == 'add': self.name = query[2] def read_queries(): n = int(input()) return [Query(input().split()) for i in range(n)] def write_responses(result): print('\n'.join(result)) def process_queries(queries): result = [] # Keep list of all existing (i.e. not deleted yet) contacts. contacts = [] for cur_query in queries: if cur_query.type == 'add': # if we already have contact with such number, # we should rewrite contact's name for contact in contacts: if contact.number == cur_query.number: contact.name = cur_query.name break else: # otherwise, just add it contacts.append(cur_query) elif cur_query.type == 'del': for j in range(len(contacts)): if contacts[j].number == cur_query.number: contacts.pop(j) break else: response = 'not found' for contact in contacts: if contact.number == cur_query.number: response = contact.name break result.append(response) return result if __name__ == '__main__': write_responses(process_queries(read_queries()))
기본코드이며 Query 클래스를 통해 입력받은 쿼리의 요소들을 분리하여 처리가 가능하고 read_queries, write_responses를 통해 입력을 받고 출력할 것들을 반환하게 된다. 마지막인 process_queries를 direct addressing을 통해 최적화를 진행해야 한다.
# python3 class Query: def __init__(self, query): self.type = query[0] self.number = int(query[1]) if self.type == 'add': self.name = query[2] def read_queries(): n = int(input()) return [Query(input().split()) for i in range(n)] def write_responses(result): print('\n'.join(result)) def process_queries(queries): result = [] # Keep list of all existing (i.e. not deleted yet) contacts. contacts = [None] * (10**7) for cur_query in queries: if cur_query.type == 'add': contacts[cur_query.number] = cur_query.name elif cur_query.type == 'del': contacts[cur_query.number] = None else: if contacts[cur_query.number] is None: result.append('not found') else: result.append(contacts[cur_query.number]) return result if __name__ == '__main__': write_responses(process_queries(read_queries()))
제약조건에 명시된 것처럼 contacts를 10^7으로 고정시켜놓고 이후 index를 통해 접근하여 바로 연산을 하는 것이 for문을 통해 작업하는 것보다 훨씬 빠를 것이다.
2번째는 chaining하는 문제이며 수식과 함께 미리 상수를 주었다.
p = 1 000 000 007, x = 263
Input format :
m (the number of buckets)
N (the number of queries)
queries
Output format :
result of find/check queries
이번에도 예시를 보면 쉽게 이해가능한데 첫번째 예시를 보면 받은 문자들에 대해 ASCII코드로 변환하고 이를 x^i과 연산 후 p로 modulo연산을 한 결과에 m으로 modulo한 값을 가지고 chaining을 한 것을 볼 수 있다. 이후에는 find/check에 대한 결과값들을 보내주게 된다.
추가적인 예시들까지 보고 overflow를 조심하라는 지시문도 확인하였다.
# python3 class Query: def __init__(self, query): self.type = query[0] if self.type == 'check': self.ind = int(query[1]) else: self.s = query[1] class QueryProcessor: _multiplier = 263 _prime = 1000000007 def __init__(self, bucket_count): self.bucket_count = bucket_count # store all strings in one list self.elems = [None] * bucket_count def _hash_func(self, s): ans = 0 for c in reversed(s): ans = (ans * self._multiplier + ord(c)) % self._prime return (ans % self.bucket_count + self.bucket_count) % self.bucket_count def write_search_result(self, was_found): print('yes' if was_found else 'no') def write_chain(self, chain): if chain != None: print(' '.join(chain)) else: print(' ') def read_query(self): return Query(input().split()) def process_query(self, query): if query.type == "check": self.write_chain(self.elems[query.ind]) else: hash_key = self._hash_func(query.s) if query.type == 'find': if self.elems[hash_key] != None and (query.s in self.elems[hash_key]): self.write_search_result(True) else: self.write_search_result(False) elif query.type == 'add': if self.elems[hash_key] == None: self.elems[hash_key] = [query.s] else: if query.s not in self.elems[hash_key]: self.elems[hash_key].insert(0, query.s) else: if self.elems[hash_key] != None and query.s in self.elems[hash_key]: self.elems[hash_key].remove(query.s) if len(self.elems[hash_key]) == 0: self.elems[hash_key] = None def process_queries(self): n = int(input()) for i in range(n): self.process_query(self.read_query()) if __name__ == '__main__': bucket_count = int(input()) proc = QueryProcessor(bucket_count) proc.process_queries()
check일 경우에는 해당 ind에 해당하는 chain을 출력하도록 하고 이외의 경우엔 find, add, del type에 따라 연산을 진행해 주도록하면 될 것이다.
3번째 문제는 hash substring에 해당하는 find pattern in text에 관한 문제이다. Rabin-Karp 알고리즘을 활용해 해결하라는 지시가 있다.
Input format :
P (pattern)
T (text)
Output format :
position (all the occurrences of P in T, ascending order)
첫번째 예시를 보자면 P = aba, T = abacaba이므로 해당 결과는 0 4가 나올 것이다.
# python3 def read_input(): return (input().rstrip(), input().rstrip()) def print_occurrences(output): print(' '.join(map(str, output))) def get_occurrences(pattern, text): return [ i for i in range(len(text) - len(pattern) + 1) if text[i:i + len(pattern)] == pattern ] if __name__ == '__main__': print_occurrences(get_occurrences(*read_input()))
기초 코드상으로는 기본적인 기능으로 구현이 되어있고 양이 방대해질수록 연산시간이 더 많이 걸리게 된다.
# python3import random def read_input(): return (input().rstrip(), input().rstrip()) def print_occurrences(output): print(' '.join(map(str, output))) def hash_func(s, p, x): ans = 0 for c in reversed(s): ans = ((ans * x + ord(c)) % p + p) % p return ans def precompute_hashes(pattern, text, p, x): result = [None] * (len(text) - len(pattern) + 1) S = text[(len(text)-len(pattern)):len(text)] result[len(text)-len(pattern)] = hash_func(S, p, x) y = 1 for i in range(1, len(pattern) + 1): y = (y * x) % p for i in range(len(text) - len(pattern) - 1, -1, -1): result[i] = (x * result[i+1] + ord(text[i]) - y * ord(text[i + len(pattern)])) % p return result def get_occurrences(pattern, text): _prime = 1000000007 x = random.randint(0, _prime) hashes = precompute_hashes(pattern, text, _prime, x) result = [] pHash = hash_func(pattern, _prime, x) for i in range(0, len(text) - len(pattern) + 1): if pHash != hashes[i]: continue if text[i:i + len(pattern)] == pattern: result.append(i) return result if __name__ == '__main__': print_occurrences(get_occurrences(*read_input()))
hash_func에서는 chaining을 위한 연산값에 대한 수식이 들어가며 precompute_hashes에서는 hash value로 대응하는 역할을 한다. get_occurrences에서는 hash value를 먼저 비교 후 동일 값에 대해서만 다시 확인하여 반환해주는 순서로 구성되어 있다.
아래 출처에 있는 글을 참고하였으며 굉장히 깔끔하게 정리되어 있는 것을 보고 감탄하였다.
출처 : https://medium.com/@ltanphat/course-2-data-structure-part-3-hash-11ccf163cb09
댓글
댓글 쓰기