From 5f928c3d938c0b44930b0b392a1ba19204de8894 Mon Sep 17 00:00:00 2001 From: Jay Mo <115325888+Jay-Mo-99@users.noreply.github.com> Date: Fri, 17 Jan 2025 14:06:40 -0500 Subject: [PATCH 01/17] Create README - LeetHub --- .../README.md | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 0211-design-add-and-search-words-data-structure/README.md diff --git a/0211-design-add-and-search-words-data-structure/README.md b/0211-design-add-and-search-words-data-structure/README.md new file mode 100644 index 000000000..d13e67b18 --- /dev/null +++ b/0211-design-add-and-search-words-data-structure/README.md @@ -0,0 +1,41 @@ +

211. Design Add and Search Words Data Structure

Medium


Design a data structure that supports adding new words and finding if a string matches any previously added string.

+ +

Implement the WordDictionary class:

+ + + +

 

+

Example:

+ +
+Input
+["WordDictionary","addWord","addWord","addWord","search","search","search","search"]
+[[],["bad"],["dad"],["mad"],["pad"],["bad"],[".ad"],["b.."]]
+Output
+[null,null,null,null,false,true,true,true]
+
+Explanation
+WordDictionary wordDictionary = new WordDictionary();
+wordDictionary.addWord("bad");
+wordDictionary.addWord("dad");
+wordDictionary.addWord("mad");
+wordDictionary.search("pad"); // return False
+wordDictionary.search("bad"); // return True
+wordDictionary.search(".ad"); // return True
+wordDictionary.search("b.."); // return True
+
+ +

 

+

Constraints:

+ + From 8006e875c83e200c1c551f985fde5d190b6fac37 Mon Sep 17 00:00:00 2001 From: Jay Mo <115325888+Jay-Mo-99@users.noreply.github.com> Date: Fri, 17 Jan 2025 14:06:40 -0500 Subject: [PATCH 02/17] Time: 1514 ms (25.2%), Space: 68 MB (13.71%) - LeetHub --- ...ign-add-and-search-words-data-structure.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 0211-design-add-and-search-words-data-structure/0211-design-add-and-search-words-data-structure.py diff --git a/0211-design-add-and-search-words-data-structure/0211-design-add-and-search-words-data-structure.py b/0211-design-add-and-search-words-data-structure/0211-design-add-and-search-words-data-structure.py new file mode 100644 index 000000000..32d7d8d52 --- /dev/null +++ b/0211-design-add-and-search-words-data-structure/0211-design-add-and-search-words-data-structure.py @@ -0,0 +1,42 @@ +class Node: + + def __init__(self): + + self.d = defaultdict(Node) + self.EOW = False + + +class WordDictionary: + + def __init__(self): + self.words = Node() + + + def addWord(self, word: str) -> None: + + cur = self.words + for ch in word: cur = cur.d[ch] + cur.EOW = True + + + def search(self, word: str) -> bool: + + return self.dfs(word, self.words) + + + def dfs(self, word: str, node: Node, i = 0) -> bool: + + if not node : return False + if i == len(word) : return node.EOW + + if word[i] == '.' : return any( + (self.dfs(word, child, i+1) + for child in node.d.values())) + + return self.dfs(word, node.d.get(word[i]), i+1) + + +# Your WordDictionary object will be instantiated and called as such: +# obj = WordDictionary() +# obj.addWord(word) +# param_2 = obj.search(word) \ No newline at end of file From b2c0bb95b960fa43286e342904b9a64ccd3f723e Mon Sep 17 00:00:00 2001 From: Jay Mo <115325888+Jay-Mo-99@users.noreply.github.com> Date: Fri, 17 Jan 2025 14:23:50 -0500 Subject: [PATCH 03/17] Time: 1514 ms (25.2%), Space: 68 MB (13.71%) - LeetHub From 3872b70ff4dd638a71ac39d73fd6b6c8f674d8ce Mon Sep 17 00:00:00 2001 From: Jay Mo <115325888+Jay-Mo-99@users.noreply.github.com> Date: Fri, 17 Jan 2025 14:25:21 -0500 Subject: [PATCH 04/17] Time: 1095 ms (82.99%), Space: 65.5 MB (43.88%) - LeetHub --- ...ign-add-and-search-words-data-structure.py | 58 ++++++++----------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/0211-design-add-and-search-words-data-structure/0211-design-add-and-search-words-data-structure.py b/0211-design-add-and-search-words-data-structure/0211-design-add-and-search-words-data-structure.py index 32d7d8d52..158dba2ba 100644 --- a/0211-design-add-and-search-words-data-structure/0211-design-add-and-search-words-data-structure.py +++ b/0211-design-add-and-search-words-data-structure/0211-design-add-and-search-words-data-structure.py @@ -1,42 +1,34 @@ -class Node: - +class TrieNode: def __init__(self): - - self.d = defaultdict(Node) - self.EOW = False - + self.children = {} + self.is_end_of_word = False class WordDictionary: - def __init__(self): - self.words = Node() - + self.root = TrieNode() def addWord(self, word: str) -> None: - - cur = self.words - for ch in word: cur = cur.d[ch] - cur.EOW = True - + node = self.root + for char in word: + if char not in node.children: + node.children[char] = TrieNode() + node = node.children[char] + node.is_end_of_word = True def search(self, word: str) -> bool: + def dfs(index, node): + if index == len(word): + return node.is_end_of_word + + char = word[index] + if char == '.': + for child in node.children.values(): + if dfs(index + 1, child): + return True + return False + else: + if char not in node.children: + return False + return dfs(index + 1, node.children[char]) - return self.dfs(word, self.words) - - - def dfs(self, word: str, node: Node, i = 0) -> bool: - - if not node : return False - if i == len(word) : return node.EOW - - if word[i] == '.' : return any( - (self.dfs(word, child, i+1) - for child in node.d.values())) - - return self.dfs(word, node.d.get(word[i]), i+1) - - -# Your WordDictionary object will be instantiated and called as such: -# obj = WordDictionary() -# obj.addWord(word) -# param_2 = obj.search(word) \ No newline at end of file + return dfs(0, self.root) From 6f7f35e210fab2e433f882f693769cb6dff34c83 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 17 Jan 2025 19:40:52 -0500 Subject: [PATCH 05/17] Analyze design and search words data structure --- .../Jay-Mo-99.py | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 design-add-and-search-words-data-structure/Jay-Mo-99.py diff --git a/design-add-and-search-words-data-structure/Jay-Mo-99.py b/design-add-and-search-words-data-structure/Jay-Mo-99.py new file mode 100644 index 000000000..3de11a1bd --- /dev/null +++ b/design-add-and-search-words-data-structure/Jay-Mo-99.py @@ -0,0 +1,120 @@ +# 해석 +# 0. TrieNode 클래스 정의: +# - 각 TrieNode 인스턴스는 다음의 두 가지 속성을 가진다: +# 1) children: 현재 노드의 자식 노드들을 저장하는 딕셔너리 (문자 -> TrieNode 인스턴스). +# 2) is_end_of_word: 현재 노드가 단어의 끝인지 나타내는 Boolean 값. + +# 1. WordDictionary 클래스 정의: +# - WordDictionary 클래스는 Trie 자료구조를 사용하여 단어를 저장(addWord)하고 탐색(search)한다. + +# 1-1. __init__ 함수: +# - root는 TrieNode 클래스로 생성된 인스턴스를 가진다. +# - Trie 자료구조의 시작점(루트 노드) 역할을 한다. + +# 1-2. addWord 함수: +# 1) 루트 노드(self.root)에서 시작. +# 2) 단어의 각 문자를 순회하며: +# - 현재 노드의 children에 문자가 없으면, 새 TrieNode를 생성해 추가. +# - 현재 노드를 해당 문자의 자식 노드로 이동. +# 3) 단어의 마지막 문자를 처리한 후, 해당 노드의 is_end_of_word를 True로 설정. + + +# 1-3. search 함수: +# - 주어진 단어가 Trie에 존재하는지 확인하는 함수. +# - 와일드카드 문자(.)를 처리할 수 있다. +# - 내부적으로 dfs(깊이 우선 탐색) 함수를 사용하여 트라이를 탐색. +# - dfs(index, node): +# 1) 종료 조건: index가 단어 길이에 도달하면, 현재 노드의 is_end_of_word 반환. +# 2) 현재 문자가 '.'인 경우: +# - 현재 노드의 모든 자식 노드에 대해 dfs를 호출. +# - 하나라도 True를 반환하면 True 반환. +# 3) 현재 문자가 일반 문자인 경우: +# - 자식 노드에 문자가 없으면 False 반환. +# - 자식 노드로 이동해 dfs를 재귀 호출. + + + + #Big O + # - N: 저장된 모든 단어의 총 문자 수 (Trie에 저장된 모든 문자의 개수). + # - C: 알파벳의 개수 (영어 기준 최대 26). + + #Time Complexity: O(N) + #- addWord함수 : N에 기반하여 단어 추가 + #- searchWord 함수: + # - 일반 탐색: O(n), n은 단어의 길이. + # - 와일드카드 탐색: 최악의 경우 O(C^N), + # - C는 알파벳 개수 (최대 26). + # - N은 단어의 길이. 와일드카드 문자가 많을수록 모든 경로를 탐색해야 할 수도 있음. + + # - Space Complexity: O(N × C) + # + # - 각 노드는: + # 1) children 딕셔너리를 통해 자식 노드를 저장 (메모리 사용). + # 2) is_end_of_word 변수 (Boolean 값, O(1)). + # - Trie에 저장된 단어의 문자 수가 많을수록 메모리 사용량 증가. + +class TrieNode: + def __init__(self): + self.children = {} #알파벳 a부터 z까지를 자식으로 가짐, 크기 26의 배열이나 딕셔너리를 사용. + self.is_end_of_word = False #어떤 단어의 끝인지 나타내는 Boolean 값 + #예를 들어, "note"이라는 단어의 'e'에 해당하는 노드의 is_end_of_word가 True, 'n' + +class WordDictionary: + def __init__(self): + self.root = TrieNode() # WD로 생성된 인스턴스.root = TrieNode 인스턴스 + + def addWord(self, word: str) -> None: + node = self.root #node에 self.root를 부여 + for char in word: # 매개변수 word를 하나씩 순회하며 char에 저장 (예: word="note" -> char="n", "o", "t", "e") + if char not in node.children: # 만약 char가 현재 노드의 자식 노드 목록에 없다면 + node.children[char] = TrieNode() + #node.children[char]을 TrideNode 인스턴스로 생성 + # self.root.children = { + # "n": TrieNode() # "n" 키가 추가되고, 값으로 새로운 TrieNode 인스턴스가 들어감 + # } + + #Example1: + #root + #└── "n" (children={}, is_end_of_word=False) + + #Example2: + #└── "n" (children={}, is_end_of_word=False) + # └── "o" (children={}, is_end_of_word=False) + node = node.children[char] #node를 현 node의 children[char]로 이동 + #Example1: + # node = node.children["n"] + + #Example2: + # node = node.children["o"] + node.is_end_of_word = True + #After for loop, 끝 노드의 is_end_of_word를 True로 전환 + + #Example 4: + #root + #└── "n" + #└── "o" + #└── "t" + #└── "e" (children={}, is_end_of_word=True) + + def search(self, word: str) -> bool: + def dfs(index, node): # DFS 함수 정의 + # 1) 종료 조건: 모든 문자를 탐색한 경우 + if index == len(word): + return node.is_end_of_word # 단어 끝 여부 반환 + # 2) 현재 문자 처리 + char = word[index] + if char == '.': # 2-1) 와일드카드인 경우 + for child in node.children.values(): # 모든 자식 노드 탐색 + if dfs(index + 1, child): #dfs를 재귀호출 하여 다음 노드로 탐색 재개 + return True #재귀 이후에 있으면 True + return False #없으면 False + else: # 2-2) 일반 문자 처리 + if char not in node.children: # 현재 문자가 자식 노드에 없는 경우 False + return False + return dfs(index + 1, node.children[char]) # 다음 노드로 이동하여 탐색 + + return dfs(0, self.root) + #1. def dfs를 self.root 위치에서 첫 호출. + + + From aa1a1accc011dd9a07c6a9346a7c0e3057837864 Mon Sep 17 00:00:00 2001 From: Jay Mo <115325888+Jay-Mo-99@users.noreply.github.com> Date: Tue, 21 Jan 2025 21:39:13 -0500 Subject: [PATCH 06/17] Create README - LeetHub --- 0206-reverse-linked-list/README.md | 34 ++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 0206-reverse-linked-list/README.md diff --git a/0206-reverse-linked-list/README.md b/0206-reverse-linked-list/README.md new file mode 100644 index 000000000..d0e5a2292 --- /dev/null +++ b/0206-reverse-linked-list/README.md @@ -0,0 +1,34 @@ +

206. Reverse Linked List

Easy


Given the head of a singly linked list, reverse the list, and return the reversed list.

+ +

 

+

Example 1:

+ +
+Input: head = [1,2,3,4,5]
+Output: [5,4,3,2,1]
+
+ +

Example 2:

+ +
+Input: head = [1,2]
+Output: [2,1]
+
+ +

Example 3:

+ +
+Input: head = []
+Output: []
+
+ +

 

+

Constraints:

+ + + +

 

+

Follow up: A linked list can be reversed either iteratively or recursively. Could you implement both?

From 67c6eb000cbe0d2bba59a069490e8514ea003412 Mon Sep 17 00:00:00 2001 From: Jay Mo <115325888+Jay-Mo-99@users.noreply.github.com> Date: Tue, 21 Jan 2025 21:39:14 -0500 Subject: [PATCH 07/17] Time: 2 ms (19.04%), Space: 16 MB (14.06%) - LeetHub --- .../0206-reverse-linked-list.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 0206-reverse-linked-list/0206-reverse-linked-list.py diff --git a/0206-reverse-linked-list/0206-reverse-linked-list.py b/0206-reverse-linked-list/0206-reverse-linked-list.py new file mode 100644 index 000000000..b48bb838b --- /dev/null +++ b/0206-reverse-linked-list/0206-reverse-linked-list.py @@ -0,0 +1,26 @@ +# Definition for singly-linked list. +# class ListNode(object): +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution(object): + def reverseList(self, head): + """ + :type head: Optional[ListNode] + :rtype: Optional[ListNode] + """ + temp =[] + while head: + temp.append(head.val) + head = head.next + + temp = temp[::-1] #Reverse the temp list + + myNode = ListNode() #Create the Listnode instance + current = myNode + + for value in temp: + current.next = ListNode(value) + current = current.next + + return myNode.next From 63ce3fdd8b964a09744b928ec2e529b996a1b09d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Jan 2025 22:44:05 -0500 Subject: [PATCH 08/17] Solve: reverse linked list --- reverse-linked-list/Jay-Mo-99.py | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 reverse-linked-list/Jay-Mo-99.py diff --git a/reverse-linked-list/Jay-Mo-99.py b/reverse-linked-list/Jay-Mo-99.py new file mode 100644 index 000000000..727884465 --- /dev/null +++ b/reverse-linked-list/Jay-Mo-99.py @@ -0,0 +1,48 @@ + #해석 + # 매개변수 head (ListNode 클래스의 인스턴스)에서 값을 추출하여 temp 리스트에 저장한다. + # temp 리스트를 역순으로 정렬(reverse)하여 연결 리스트를 뒤집는다. + # temp 리스트의 각 값을 ListNode 클래스를 사용해 새 연결 리스트(myNode)를 생성하며 순서대로 추가한다. + # 최종적으로 myNode의 next를 반환한다(이것은 새 연결 리스트의 시작점을 가리킨다). + + + #Big O + #- N: 입력 연결 리스트(head)의 노드 갯수 + + #Time Complexity: O(N) + #- while head: 연결 리스트의 모든 노드를 순회하며 val을 temp에 저장하므로 O(N). + #- for value in temp: temp 리스트의 모든 값을 순회하며 새로운 노드를 생성하므로 O(N). + + #Space Complexity: O(N) + #- temp : 연결 리스트의 모든 val을 저장하므로 O(N). + #- myNode 인스턴스: for loop 동안 current.next에 ListNode 인스턴스를 생성한다. 이 작업은 O(1) 작업이 N번 반복되므로 O(N). + + +# Definition for singly-linked list. +# class ListNode(object): +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution(object): + def reverseList(self, head): + """ + :type head: Optional[ListNode] + :rtype: Optional[ListNode] + """ + temp =[] + while head: + temp.append(head.val) + head = head.next + + temp = temp[::-1] #Reverse the temp list + + myNode = ListNode() #Create the Listnode instance + current = myNode #Update current to myNode for Initialize + + for value in temp: + current.next = ListNode(value) ## Create new ListNode Instance and assign it to current.next , + current = current.next #Move to the current.next(new Instance base on ListNode ) + + return myNode.next ## Return the head of the newly created linked list + + + From d13ff9e0c1e1849be274d3e547d1ed5c5843c917 Mon Sep 17 00:00:00 2001 From: Jay Mo <115325888+Jay-Mo-99@users.noreply.github.com> Date: Tue, 21 Jan 2025 23:00:14 -0500 Subject: [PATCH 09/17] Delete 0211-design-add-and-search-words-data-structure/README.md --- .../README.md | 41 ------------------- 1 file changed, 41 deletions(-) delete mode 100644 0211-design-add-and-search-words-data-structure/README.md diff --git a/0211-design-add-and-search-words-data-structure/README.md b/0211-design-add-and-search-words-data-structure/README.md deleted file mode 100644 index d13e67b18..000000000 --- a/0211-design-add-and-search-words-data-structure/README.md +++ /dev/null @@ -1,41 +0,0 @@ -

211. Design Add and Search Words Data Structure

Medium


Design a data structure that supports adding new words and finding if a string matches any previously added string.

- -

Implement the WordDictionary class:

- - - -

 

-

Example:

- -
-Input
-["WordDictionary","addWord","addWord","addWord","search","search","search","search"]
-[[],["bad"],["dad"],["mad"],["pad"],["bad"],[".ad"],["b.."]]
-Output
-[null,null,null,null,false,true,true,true]
-
-Explanation
-WordDictionary wordDictionary = new WordDictionary();
-wordDictionary.addWord("bad");
-wordDictionary.addWord("dad");
-wordDictionary.addWord("mad");
-wordDictionary.search("pad"); // return False
-wordDictionary.search("bad"); // return True
-wordDictionary.search(".ad"); // return True
-wordDictionary.search("b.."); // return True
-
- -

 

-

Constraints:

- - From 784e9b6b97cb74c01d8cc79e99b72e6fe408ea3c Mon Sep 17 00:00:00 2001 From: Jay Mo <115325888+Jay-Mo-99@users.noreply.github.com> Date: Tue, 21 Jan 2025 23:00:53 -0500 Subject: [PATCH 10/17] Delete 0206-reverse-linked-list/README.md --- 0206-reverse-linked-list/README.md | 34 ------------------------------ 1 file changed, 34 deletions(-) delete mode 100644 0206-reverse-linked-list/README.md diff --git a/0206-reverse-linked-list/README.md b/0206-reverse-linked-list/README.md deleted file mode 100644 index d0e5a2292..000000000 --- a/0206-reverse-linked-list/README.md +++ /dev/null @@ -1,34 +0,0 @@ -

206. Reverse Linked List

Easy


Given the head of a singly linked list, reverse the list, and return the reversed list.

- -

 

-

Example 1:

- -
-Input: head = [1,2,3,4,5]
-Output: [5,4,3,2,1]
-
- -

Example 2:

- -
-Input: head = [1,2]
-Output: [2,1]
-
- -

Example 3:

- -
-Input: head = []
-Output: []
-
- -

 

-

Constraints:

- - - -

 

-

Follow up: A linked list can be reversed either iteratively or recursively. Could you implement both?

From e6dbc47d37dda979e3aad4834cd16dbb289f3e4f Mon Sep 17 00:00:00 2001 From: Jay Mo <115325888+Jay-Mo-99@users.noreply.github.com> Date: Tue, 21 Jan 2025 23:01:53 -0500 Subject: [PATCH 11/17] Delete 0206-reverse-linked-list/0206-reverse-linked-list.py --- .../0206-reverse-linked-list.py | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 0206-reverse-linked-list/0206-reverse-linked-list.py diff --git a/0206-reverse-linked-list/0206-reverse-linked-list.py b/0206-reverse-linked-list/0206-reverse-linked-list.py deleted file mode 100644 index b48bb838b..000000000 --- a/0206-reverse-linked-list/0206-reverse-linked-list.py +++ /dev/null @@ -1,26 +0,0 @@ -# Definition for singly-linked list. -# class ListNode(object): -# def __init__(self, val=0, next=None): -# self.val = val -# self.next = next -class Solution(object): - def reverseList(self, head): - """ - :type head: Optional[ListNode] - :rtype: Optional[ListNode] - """ - temp =[] - while head: - temp.append(head.val) - head = head.next - - temp = temp[::-1] #Reverse the temp list - - myNode = ListNode() #Create the Listnode instance - current = myNode - - for value in temp: - current.next = ListNode(value) - current = current.next - - return myNode.next From f501a9dd22eda9ea861415202ee5276b6f720a3d Mon Sep 17 00:00:00 2001 From: Jay Mo <115325888+Jay-Mo-99@users.noreply.github.com> Date: Tue, 21 Jan 2025 23:02:06 -0500 Subject: [PATCH 12/17] Delete 0211-design-add-and-search-words-data-structure/0211-design-add-and-search-words-data-structure.py --- ...ign-add-and-search-words-data-structure.py | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 0211-design-add-and-search-words-data-structure/0211-design-add-and-search-words-data-structure.py diff --git a/0211-design-add-and-search-words-data-structure/0211-design-add-and-search-words-data-structure.py b/0211-design-add-and-search-words-data-structure/0211-design-add-and-search-words-data-structure.py deleted file mode 100644 index 158dba2ba..000000000 --- a/0211-design-add-and-search-words-data-structure/0211-design-add-and-search-words-data-structure.py +++ /dev/null @@ -1,34 +0,0 @@ -class TrieNode: - def __init__(self): - self.children = {} - self.is_end_of_word = False - -class WordDictionary: - def __init__(self): - self.root = TrieNode() - - def addWord(self, word: str) -> None: - node = self.root - for char in word: - if char not in node.children: - node.children[char] = TrieNode() - node = node.children[char] - node.is_end_of_word = True - - def search(self, word: str) -> bool: - def dfs(index, node): - if index == len(word): - return node.is_end_of_word - - char = word[index] - if char == '.': - for child in node.children.values(): - if dfs(index + 1, child): - return True - return False - else: - if char not in node.children: - return False - return dfs(index + 1, node.children[char]) - - return dfs(0, self.root) From 18fee1f8b5686434181c4b769c61e4f4fee7be5d Mon Sep 17 00:00:00 2001 From: Jay Mo <115325888+Jay-Mo-99@users.noreply.github.com> Date: Tue, 21 Jan 2025 23:02:36 -0500 Subject: [PATCH 13/17] Delete design-add-and-search-words-data-structure/Jay-Mo-99.py --- .../Jay-Mo-99.py | 129 ------------------ 1 file changed, 129 deletions(-) delete mode 100644 design-add-and-search-words-data-structure/Jay-Mo-99.py diff --git a/design-add-and-search-words-data-structure/Jay-Mo-99.py b/design-add-and-search-words-data-structure/Jay-Mo-99.py deleted file mode 100644 index d31c372c5..000000000 --- a/design-add-and-search-words-data-structure/Jay-Mo-99.py +++ /dev/null @@ -1,129 +0,0 @@ -# 해석 - -# 0. TrieNode 클래스 정의: -# - 각 TrieNode 인스턴스는 다음의 두 가지 속성을 가진다: -# 1) children: 현재 노드의 자식 노드들을 저장하는 딕셔너리 (문자 -> TrieNode 인스턴스). -# 2) is_end_of_word: 현재 노드가 단어의 끝인지 나타내는 Boolean 값. - -# 1. WordDictionary 클래스 정의: -# - WordDictionary 클래스는 Trie 자료구조를 사용하여 단어를 저장(addWord)하고 탐색(search)한다. - -# 1-1. __init__ 함수: -# - root는 TrieNode 클래스로 생성된 인스턴스를 가진다. -# - Trie 자료구조의 시작점(루트 노드) 역할을 한다. - -# 1-2. addWord 함수: -# 1) 루트 노드(self.root)에서 시작. -# 2) 단어의 각 문자를 순회하며: -# - 현재 노드의 children에 문자가 없으면, 새 TrieNode를 생성해 추가. -# - 현재 노드를 해당 문자의 자식 노드로 이동. -# 3) 단어의 마지막 문자를 처리한 후, 해당 노드의 is_end_of_word를 True로 설정. - - -# 1-3. search 함수: -# - 주어진 단어가 Trie에 존재하는지 확인하는 함수. -# - 와일드카드 문자(.)를 처리할 수 있다. -# - 내부적으로 dfs(깊이 우선 탐색) 함수를 사용하여 트라이를 탐색. -# - dfs(index, node): -# 1) 종료 조건: index가 단어 길이에 도달하면, 현재 노드의 is_end_of_word 반환. -# 2) 현재 문자가 '.'인 경우: -# - 현재 노드의 모든 자식 노드에 대해 dfs를 호출. -# - 하나라도 True를 반환하면 True 반환. -# 3) 현재 문자가 일반 문자인 경우: -# - 자식 노드에 문자가 없으면 False 반환. -# - 자식 노드로 이동해 dfs를 재귀 호출. - - - - #Big O - # - N: 저장된 모든 단어의 총 문자 수 (Trie에 저장된 모든 문자의 개수). - # - C: 알파벳의 개수 (영어 기준 최대 26). - - #Time Complexity: O(N) - #- addWord함수 : N에 기반하여 단어 추가 - #- searchWord 함수: - # - 일반 탐색: O(n), n은 단어의 길이. - # - 와일드카드 탐색: 최악의 경우 O(C^N), - # - C는 알파벳 개수 (최대 26). - # - N은 단어의 길이. 와일드카드 문자가 많을수록 모든 경로를 탐색해야 할 수도 있음. - - # - Space Complexity: O(N × C) - # - # - 각 노드는: - # 1) children 딕셔너리를 통해 자식 노드를 저장 (메모리 사용). - # 2) is_end_of_word 변수 (Boolean 값, O(1)). - # - Trie에 저장된 단어의 문자 수가 많을수록 메모리 사용량 증가. - -class TrieNode: - def __init__(self): - self.children = {} #알파벳 a부터 z까지를 자식으로 가짐, 크기 26의 배열이나 딕셔너리를 사용. - self.is_end_of_word = False #어떤 단어의 끝인지 나타내는 Boolean 값 - #예를 들어, "note"이라는 단어의 'e'에 해당하는 노드의 is_end_of_word가 True, 'n' - -class WordDictionary: - def __init__(self): - self.root = TrieNode() # WD로 생성된 인스턴스.root = TrieNode 인스턴스 - - def addWord(self, word: str) -> None: - node = self.root #node에 self.root를 부여 - for char in word: # 매개변수 word를 하나씩 순회하며 char에 저장 (예: word="note" -> char="n", "o", "t", "e") - if char not in node.children: # 만약 char가 현재 노드의 자식 노드 목록에 없다면 - node.children[char] = TrieNode() - #node.children[char]을 TrideNode 인스턴스로 생성 - # self.root.children = { - # "n": TrieNode() # "n" 키가 추가되고, 값으로 새로운 TrieNode 인스턴스가 들어감 - # } - - #Example1: - #root - #└── "n" (children={}, is_end_of_word=False) - - #Example2: - #└── "n" (children={}, is_end_of_word=False) - # └── "o" (children={}, is_end_of_word=False) - node = node.children[char] #node를 현 node의 children[char]로 이동 - #Example1: - # node = node.children["n"] - - #Example2: - # node = node.children["o"] - node.is_end_of_word = True - #After for loop, 끝 노드의 is_end_of_word를 True로 전환 - - #Example 4: - #root - #└── "n" - #└── "o" - #└── "t" - #└── "e" (children={}, is_end_of_word=True) - - def search(self, word: str) -> bool: - def dfs(index, node): # DFS 함수 정의 - # 1) 종료 조건: 모든 문자를 탐색한 경우 - if index == len(word): - return node.is_end_of_word # 단어 끝 여부 반환 - # 2) 현재 문자 처리 - char = word[index] - if char == '.': # 2-1) 와일드카드인 경우 - for child in node.children.values(): # 모든 자식 노드 탐색 - if dfs(index + 1, child): #dfs를 재귀호출 하여 다음 노드로 탐색 재개 - return True #재귀 이후에 있으면 True - return False #없으면 False - else: # 2-2) 일반 문자 처리 - if char not in node.children: # 현재 문자가 자식 노드에 없는 경우 False - return False - return dfs(index + 1, node.children[char]) # 다음 노드로 이동하여 탐색 - - return dfs(0, self.root) - #1. def dfs를 self.root 위치에서 첫 호출. - - - - - - - - - - - From 222b461311752e2315fdb31832ee14a45ab43fec Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Jan 2025 18:25:12 -0500 Subject: [PATCH 14/17] Solve: Longest Substring Without Repeating Characters --- .../Jay-Mo-99.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 longest-substring-without-repeating-characters/Jay-Mo-99.py diff --git a/longest-substring-without-repeating-characters/Jay-Mo-99.py b/longest-substring-without-repeating-characters/Jay-Mo-99.py new file mode 100644 index 000000000..3ddf70e67 --- /dev/null +++ b/longest-substring-without-repeating-characters/Jay-Mo-99.py @@ -0,0 +1,36 @@ + #해석 + # + + + #Big O + #- N: str s의 길이 + + #Time Complexity: O(N) + #- start,end: 각각 최대 N번 움직임 -> O(N) + #- set의 삽입, 삭제 -> O(1) + + #Space Complexity: O(N) + #- chars: 최악의 경우 chars는 s의 모든 char을 저장한다 -> O(N) + +class Solution: + def lengthOfLongestSubstring(self, s: str) -> int: + max_len = 0 + chars = set() #현 윈도우 내 중복 없이 존재하는 문자들을 저장하는 set + start, end = 0, 0 # 슬라이딩 윈도우의 start 인덱스, end 인덱스 + #end가 s의 마지막 인덱스에 도달할때까지 반복 + while end < len(s): + #s[end]가 chars에 존재하면 + if s[end] in chars: + #chars의 s[start]를 제거 + chars.remove(s[start]) + #start를 오른쪽으로 이동, 윈도우 축소 + start += 1 + else: #s[end] 가 chars에 존재하지 않으면 + chars.add(s[end]) #해당 s[end]를 chars에 추가해준다 + end += 1 #end를 오른쪽으로 옮겨 윈도우 확장 + max_len = max(end - start, max_len) #start-end 계산하여 update + return max_len + +mySolution = Solution() +mySolution.lengthOfLongestSubstring("pwwkew") + From 80b661aa86b0766eb87d971d73d53d8159108fcb Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Jan 2025 23:18:02 -0500 Subject: [PATCH 15/17] Solve: number of islands --- number-of-islands/Jay-Mo-99.py | 60 ++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 number-of-islands/Jay-Mo-99.py diff --git a/number-of-islands/Jay-Mo-99.py b/number-of-islands/Jay-Mo-99.py new file mode 100644 index 000000000..c04b294b1 --- /dev/null +++ b/number-of-islands/Jay-Mo-99.py @@ -0,0 +1,60 @@ + #해석 + # r,c nested loop로 grid의 모든 element를 검사한다 + # 만약 1인 element를 만나면 sink함수를 호출한다 + # -sink 함수는 해당 element를 0으로 만들고 해당 element의 좌,우,상,하가 1인지 체크한다 + # -만약 1이 있다면 또 sink를 반복 호출하며 위의 검사를 반복한다.(1이 없을때까지) + # -만약 더이상 연결된 1이 없다면 재귀 호출 종료. + # sink함수 종료 시시 nested loop로 돌아와서 이후후 1인 element를 찾는다. + # grid의 1이 sink로 모두 없어지면 return cls한다. + + + #Big O + #- M: grid의 행의 갯수(r) + #- N: grid의 열의 갯수(c) + + #Time Complexity: O(M*N) + #- for loop: 이중 루프로 grid의 모든 element에 도달 -> O(M*N) + #- sink(row,col): 최악의 경우 sink함수는 M*N번 호출 -> O(M*N) + + #Space Complexity: O(M∗N) + #- sink 재귀호출: + # 최악의 경우 sink함수는 스택에 M*N번 재귀 호출 당한다. + # 스택에 해당 메모리 누적(재귀 호출 스택의 깊이가 M*N) -> O(M*N) +from typing import List +class Solution: + def numIslands(self, grid: List[List[str]]) -> int: + def sink(row, col): + grid[row][col] = "0" + + for r, c in [ + (row, col - 1), #Left + (row, col + 1), #Right + (row - 1, col), #Up + (row + 1, col), #Down + ]: + # If the neighbor cell is within bounds and is land ("1"), sink it recursively. + if 0 <= r < len(grid) and 0 <= c < len(grid[r]): + if grid[r][c] == "1": + sink(r, c) + + cnt = 0 # Count the number of islands. + # Loop through every cell in the grid. + for r in range(len(grid)): + for c in range(len(grid[r])): + if grid[r][c] == "1": + cnt += 1 + sink(r, c) ## Sink the entire island by converting all connected "1"s to "0"s. + return cnt + +mySolution = Solution() +mySolution.numIslands( + [ + ["1","1","1","1","0"], + ["1","1","0","1","0"], + ["1","1","0","0","0"], + ["0","0","0","0","0"] + ] +) + + + From f1874c86a49abe3ef869817f92a5d3b8bfec50f5 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 24 Jan 2025 17:54:08 -0500 Subject: [PATCH 16/17] Solve: unique-paths --- unique-paths/Jay-Mo-99.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 unique-paths/Jay-Mo-99.py diff --git a/unique-paths/Jay-Mo-99.py b/unique-paths/Jay-Mo-99.py new file mode 100644 index 000000000..0d27adec2 --- /dev/null +++ b/unique-paths/Jay-Mo-99.py @@ -0,0 +1,37 @@ + # 해석 + # grid는 행렬(matrix)처럼 격자의 형태이다. + # 행이 m개라는 뜻은 좌표 상 (0,0), (1,0), ..., (m-1,0)까지 존재한다는 뜻이다. + # 열이 n개라는 뜻은 좌표 상 (0,0), (0,1), ..., (0,n-1)까지 존재한다는 뜻이다. + # 따라서 (0,0)에서 (m-1,n-1)까지의 모든 가능한 경로 수를 구해야 한다. + # - 아래로 m-1번 이동하고, 오른쪽으로 n-1번 이동해야 한다. + # - 총 이동 횟수는 m-1 + n-1 = m+n-2이다. + # - 총 이동 횟수 내부에서 아래로 m-1번 오른쪽으로 (n-1)번의 조합의 경우의 수를 구한다. + # - 예를 들어, 아래로 3번 오른쪽으로 다섯번으로 만들수 있는 모든 경우의 수를 구한다 ^^^>>>>> : ^와 > 가능한 조합을 찾아준다. + # 공식: (m+n-2)! / (m-1)! / (n-1)! + + + #Big O + #- N: int m의 크기 + #- K: int n의 크기 + + #Time Complexity: O(M+K) + #- for i in range(1,m+1-1): m과 n의 크기의 합에 영향받아 계산 진행 -> O(N+K) + + #Space Complexity: O(1) + #- up,down1,down2 - 변수와 변수를 업데이트하는 사칙연산은 상수로 여겨져 O(1), +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + up = 1 #분자 + down1 = 1 #분모 1 + down2=1 #분모 2 + + + for i in range(1,m+n-1): + up *= i + for i in range(1,m): + down1 *= i + for i in range(1,n): + down2 *= i + + return int(up/(down1*down2)) + From a8812180165a91febc74f4287863f0981eb8f371 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 24 Jan 2025 18:37:48 -0500 Subject: [PATCH 17/17] Solve: set-matrix-zeroes --- set-matrix-zeroes/Jay-Mo-99.py | 45 ++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 set-matrix-zeroes/Jay-Mo-99.py diff --git a/set-matrix-zeroes/Jay-Mo-99.py b/set-matrix-zeroes/Jay-Mo-99.py new file mode 100644 index 000000000..ff4f722dd --- /dev/null +++ b/set-matrix-zeroes/Jay-Mo-99.py @@ -0,0 +1,45 @@ + #해석 + # matrix의 모든 element를 검사한다, 만약 0을 발견하면 해당 element와 같은 row와 col을 가진 element를 "a" 로 바꾼다. + # 두번째로 matrix의 모든 element를 검사한다, 만약 a를 발견하면 이를 0으로 바꾼다. + + + #Big O + #- N: row의 크기(matrix 행의 갯수) + #- K: col의 크기(matrix 열의 갯수 ) + + #Time Complexity: O(N*K*(N+K)) + #- for nested loop : 행의 갯수(N) 당 열의 갯수만큼(K) 루프 작동 -> O(N*K) + # - 최악의 경우, 첫번째 루프에서 for i in range(rows)가 M번 발동, for j in range(cols)가 N번 발동 -> O(N+K) + + #Space Complexity: O(1) + #- rows, cols: 변수의 할당과 업데이트는 상수 취급한다 -> O(1) +from typing import List + + +class Solution: + def setZeroes(self, matrix: List[List[int]]) -> None: + """ + Do not return anything, modify matrix in-place instead. + """ + rows, cols = len(matrix), len(matrix[0]) #rows와 cols에 matrix의 좌표 부여 + + # 1차 matrix 순회: 0을 발견하면, 그 element의 같은 행과 열의 0이 아닌 수를 임시 값 "a"로 바꾸기 + for r in range(rows): + for c in range(cols): + if matrix[r][c] == 0: + # 해당 행과 열의 0이 아닌 모든 값을 임시로 "a"로 변경 + for i in range(rows): # 해당 열의 모든 값 + if matrix[i][c] != 0: + matrix[i][c] = "a" + for j in range(cols): # 해당 행의 0이 아닌 모든 값을 "a"로 변경 + if matrix[r][j] != 0: + matrix[r][j] = "a" + + # 2차 matrix순회: "a"를 가진 수를 0으로 바꿔준다. + for r in range(rows): + for c in range(cols): + if matrix[r][c] == "a": + matrix[r][c] = 0 + + +