diff --git a/best-time-to-buy-and-sell-stock/sungjinwi.py b/best-time-to-buy-and-sell-stock/sungjinwi.py new file mode 100644 index 000000000..97eae284b --- /dev/null +++ b/best-time-to-buy-and-sell-stock/sungjinwi.py @@ -0,0 +1,21 @@ +""" + TC : O(N) + for문 한 번 => O(N) + + SC : O(1) + 변수 3개 선언 이외에 추가적으로 사용하는 메모리 없으므로 +""" + +class Solution: + def maxProfit(self, prices: List[int]) -> int: + max_profit = 0 + buy = prices[0] + sell = prices[0] + for price in prices: + if price < buy: + buy = price + sell = price + if price > sell: + sell = price + max_profit = max(max_profit, sell - buy) + return max_profit diff --git a/group-anagrams/sungjinwi.py b/group-anagrams/sungjinwi.py new file mode 100644 index 000000000..5d104e923 --- /dev/null +++ b/group-anagrams/sungjinwi.py @@ -0,0 +1,34 @@ +""" + anagram은 sort하면 동일하다는 성질을 이용해서 + sorted str을 key로 문자열 str배열을 value로 가지는 딕셔너리를 만든다 + ans은 컴프리헨션을 이용해 딕셔너리의 value를 배열에 넣어 만든다 + + TC : O(WlogW * N) + strs의 평균문자열길이 W, strs의 개수를 N이라고 할 떄 + sort의 시간복잡도 => WlogW + for문 => N + + SC : O(W * N) + anagrams가 차지하는 공간은 문자열의 길이와 개수에 비례한다 + + + - defaultdict 만들 때 인자로 빈배열([])이 아닌 타입(list)을 넣어줘야한다 + + - 알고달레의 다른풀이로 문자열에 나오는 알파벳 빈도 수(count = [0] * 26)로 anagram을 판별하는 법도 있다 + 딕셔너리의 key는 불변해야 하기 때문에 count를 튜플로 바꾸는 것 주의 + +""" + +from collections import defaultdict + +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + anagrams = defaultdict(list) + for s in strs: + sorted_s = "".join(sorted(s)) + if sorted_s in anagrams: + anagrams[sorted_s].append(s) + else: + anagrams[sorted_s] = [s] + ans = [value for value in anagrams.values()] + return ans diff --git a/implement-trie-prefix-tree/sungjinwi.py b/implement-trie-prefix-tree/sungjinwi.py new file mode 100644 index 000000000..a410f62d8 --- /dev/null +++ b/implement-trie-prefix-tree/sungjinwi.py @@ -0,0 +1,65 @@ +""" + 풀이 : 딕셔너리를 통해 트리구현 + - 생성자 함수는 맨 처음 노드를 만드는 역할, search("")를 위해 "ending":True로 초기화 + - insert함수를 수행하면 노드는 다음 문자에 대해서도 각각 노드를 가지고 있음 + ex) insert("a"); insert("b") + { + "ending":True, + "a" :{"ending":True}, + "b" :{"ending":True} + } + - insert(): word의 순서대로 다음 문자의 노드(존재하지 않으면 {"ending":False}로 초기화)로 이동함 + for문 끝난 후 마지막 문자에서는 해당 노드로 끝나는 단어가 있다는 의미로 "ending":True로 수정 + + - search(): word 다음 문자의 노드로 이동하면서 존재하지 않으면 return False + 문자의 끝에 도달하면 끝나는 단어가 있는지 node["ending"] return + + - startsWith(): prefix 다음 문자의 노드로 이동하면서 존재하지 않으면 return False + 문자의 끝에 도달하면 return True + + TC : O(N) + 단어의 길이(N)에 비례한다 + SC : O(N) + insert할 단어의 길이(N)에 비례해서 노드가 생성된다 + + - 딕셔너리가 아닌 class로 풀이할 수도 있다 +""" + +class Trie: + + def __init__(self): + self.root = {"ending":True} + + def insert(self, word: str) -> None: + node = self.root + for char in word: + if char not in node: + node[char] = {"ending": False} + node = node[char] + node["ending"] = True + + def search(self, word: str) -> bool: + node = self.root + for char in word: + if char in node: + node = node[char] + else: + return False + return node["ending"] + + + def startsWith(self, prefix: str) -> bool: + node = self.root + for char in prefix: + if char in node: + node = node[char] + else: + return False + return True + + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) diff --git a/word-break/sungjinwi.py b/word-break/sungjinwi.py new file mode 100644 index 000000000..57f4d6fc6 --- /dev/null +++ b/word-break/sungjinwi.py @@ -0,0 +1,37 @@ +""" + 풀이 : + dp 배열은 s에서 길이n까지의 문자열이 word를 통해 만들어질 수 있는지 여부를 저장 + dp[0]은 빈 문자열이므로 True 나머지는 False로 초기화 (총 길이가 len(s) + 1) + wordDict를 순회하면서 + 길이 n까지의 문자열이 word로 끝나는지 + n - len(word) 길이가 word로 만들어질 수 있는지 (dp[n - len(word)]) + + 두 조건 만족하면 dp[n]=True + dp의 마지막 성분을 return + + + word의 갯수 W, 문자열 s의 길이 S + + TC : O(S^2 * W) + 각각에 대해 for문 -> S * W + s에서 word와 비교할 부분문자열 만들 때 -> S + + SC : O(S) + len(s)만큼 배열 dp를 할당 + + 유의사항 + - dp의 첫번째 요소 + - if dp[n]일 때 break를 통해 최적화할 것 + - TC구할 때 부분문자열 구하는 복잡도 고려 +""" + +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> bool: + dp = [True] + [False] * len(s) + for n in range(1, len(s) + 1): + for word in wordDict: + if s[n - len(word):n] == word and dp[n - len(word)]: + dp[n] = True + if dp[n]: + break + return dp[-1]