diff --git a/best-time-to-buy-and-sell-stock/hyogshin.py b/best-time-to-buy-and-sell-stock/hyogshin.py new file mode 100644 index 000000000..8247d1876 --- /dev/null +++ b/best-time-to-buy-and-sell-stock/hyogshin.py @@ -0,0 +1,21 @@ +''' +문제 풀이 +- 이중 for 문으로 구현시 O(n^2) 으로 시간 초과 +- least_num에 현재 날짜 이전에 가장 싸게 살 수 있는 금액을 업데이트 +- dp로 해당 날짜까지 가장 큰 수익을 저장 +시간 복잡도: O(n) +- for 문 하나 -> O(n) +공간 복잡도: O(1) +- 상수 변수만 사용 -> O(1) +''' + +class Solution: + def maxProfit(self, prices: List[int]) -> int: + largest = 0 + least = prices[0] + for i in range(len(prices)): + least = min(prices[i], least) + largest = max(prices[i] - least, largest) + return largest + + diff --git a/encode-and-decode-strings/hyogshin.py b/encode-and-decode-strings/hyogshin.py new file mode 100644 index 000000000..2cf8ade04 --- /dev/null +++ b/encode-and-decode-strings/hyogshin.py @@ -0,0 +1,56 @@ +""" +풀이 방법 +- 암호화 시 (단어의 개수) + '#' + (단어) 형식 사용 + +시간 복잡도: O(n) +- encode: join 이 모든 문자열을 이어붙임 -> O(n) +- decode: while 문 -> O(n) + +공간 복잡도: O(n) +- encode: 새로운 문자열 생성 -> O(n) +- decode: ans 리스트 -> O(n) +""" + +from typing import List +class Solution: + """ + @param: strs: a list of strings + @return: encodes a list of strings to a single string. + """ + def encode(self, strs): + return ''.join(f'{len(s)}#{s}' for s in strs) + + """ + @param: str: A string + @return: decodes a single string to a list of strings + """ + def decode(self, s): + + ans = [] + i = 0 + while i < len(s): + j = i + while s[j] != '#': + j += 1 + length = int(s[i:j]) + start = j + 1 + end = start + length + ans.append(s[start:end]) + + i = end + return ans + +if __name__ == "__main__": + sol = Solution() + + cases = [ + ["abc", "a#b", "", "hello"], + ["", ""], # 빈 문자열 2개 + ["#", "##", "###"], # 해시 포함 + ] + for arr in cases: + enc = sol.encode(arr) + dec = sol.decode(enc) + print(arr == dec, arr, "->", enc[:50] + ("..." if len(enc) > 50 else "")) + + diff --git a/group-anagrams/hyogshin.py b/group-anagrams/hyogshin.py new file mode 100644 index 000000000..40a6e26c5 --- /dev/null +++ b/group-anagrams/hyogshin.py @@ -0,0 +1,29 @@ +""" +풀이 방법 +- ord 함수를 이용해서 캐릭터 수를 기준으로 애너그램 구분 +- tuple 활용해서 키로 사용 + +시간 복잡도: O(n * k) +- 중첩 for loop: O(n * k) + +공간 복잡도: O(n) +- cnt 문자열: O(1) +- groups dict: O(n) +""" + +from collections import defaultdict +from typing import List +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + groups = defaultdict(list) + for s in strs: + cnt = [0] * 26 + for ch in s: + cnt[ord(ch) - ord('a')] += 1 + groups[tuple(cnt)].append(s) + return list(groups.values()) + +if __name__ == "__main__": + sol = Solution() + print(sol.groupAnagrams(["eat","tea","tan","ate","nat","bat"])) + diff --git a/implement-trie-prefix-tree/hyogshin.py b/implement-trie-prefix-tree/hyogshin.py new file mode 100644 index 000000000..e7a07cc96 --- /dev/null +++ b/implement-trie-prefix-tree/hyogshin.py @@ -0,0 +1,73 @@ +""" +풀이 방법 +- insert: 입력된 단어의 캐릭터로 for loop을 돌아 node.children에 없는 캐릭터라면 추가하고 있다면 node.isEnd = True +- search: 입력된 단어를 캐릭터 단위로 for loop을 돌고 node.children에 없다면 바로 False 반환, 만약 모든 캐릭터가 있는 경우 단어있는 확인하기 위해 isEnd 체크 +- startsWith: 입력된 prefix로 for loop을 돌아 node.children에 없다면 바로 False 반환 + +시간 복잡도: O(n) +- for loop -> O(n) + +공간 복잡도: O(n) +- Trie를 저장하는 공간 -> O(n) +""" + +from typing import List + +class TrieNode: + def __init__(self): + self.children = {} + self.isEnd = False + +class Trie: + + def __init__(self): + self.root = TrieNode() + + def insert(self, word: str) -> None: + node = self.root + for ch in word: + if ch not in node.children: + node.children[ch] = TrieNode() + node = node.children[ch] + node.isEnd = True + + def search(self, word: str) -> bool: + node = self.root + for ch in word: + if ch not in node.children: + return False + node = node.children[ch] + return node.isEnd + + def startsWith(self, prefix: str) -> bool: + node = self.root + for ch in prefix: + if ch not in node.children: + return False + node = node.children[ch] + return True + +if __name__ == "__main__": + trie = Trie() + + # insert & search 테스트 + trie.insert("apple") + print(trie.search("apple")) # True + print(trie.search("app")) # False + print(trie.startsWith("app")) # True + + trie.insert("app") + print(trie.search("app")) # True + + # 추가 케이스 + trie.insert("application") + print(trie.search("application")) # True + print(trie.startsWith("appl")) # True + print(trie.search("apply")) # False + + trie.insert("bat") + trie.insert("bath") + print(trie.search("bat")) # True + print(trie.startsWith("ba")) # True + print(trie.search("bad")) # False + diff --git a/word-break/hyogshin.py b/word-break/hyogshin.py new file mode 100644 index 000000000..f8990767c --- /dev/null +++ b/word-break/hyogshin.py @@ -0,0 +1,28 @@ +""" +풀이 방법 +- for 루프로 주어진 문자열을 돌면서 wordDict에 있는 단어와 매칭되면 해당 인덱스 dp를 True로 변경 +- True인 dp로부터 또 다른 단어가 사전에 매칭되면 다시 dp를 True로 변경 +- 문자열 길이 인덱스의 dp[len(str)] 가 True인 경우 모든 단어가 사전에 있는 단어로 대체 가능하므로 True 반환 + +시간 복잡도: O(n^2) +- for loop * n + for loop * 최대 n -> O(n^2) +- s[j:i] 를 wordDict에서 찾는 행위 -> O(m) + +공간 복잡도: O(n) +- dp 배열 크기 -> O(n) +- wordDict 크기 -> O(m) +""" + +from typing import List + +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> bool: + dp = [False] * (len(s) + 1) + dp[0] = True + for i in range(1, len(s) + 1): + for j in range(i): + if dp[j] and s[j:i] in wordDict: + dp[i] = True + break + return dp[len(s)] +