From f51191846fec85772f6305c1de0ea38d8331cb37 Mon Sep 17 00:00:00 2001 From: EGON Date: Thu, 14 Nov 2024 16:00:13 +0900 Subject: [PATCH 1/5] feat: solve #290 with python --- word-search-ii/EGON.py | 112 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 word-search-ii/EGON.py diff --git a/word-search-ii/EGON.py b/word-search-ii/EGON.py new file mode 100644 index 000000000..6218f9d17 --- /dev/null +++ b/word-search-ii/EGON.py @@ -0,0 +1,112 @@ +from typing import List +from unittest import TestCase, main + + +class Node: + + def __init__(self, key, data=None): + self.key = key + self.data = data + self.children = {} + + +class Trie: + + def __init__(self): + self.root = Node(None) + + def insert(self, word: str) -> None: + curr_node = self.root + for char in word: + if char not in curr_node.children: + curr_node.children[char] = Node(char) + + curr_node = curr_node.children[char] + + curr_node.data = word + + +class Solution: + def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: + return self.solve_trie_dfs(board, words) + + """ + * Constraints: + 1. m == board.length + 2. n == board[i].length + 3. 1 <= m, n <= 12 + 4. board[i][j] is a lowercase English letter. + 5. 1 <= words.length <= 3 * 104 + 6. 1 <= words[i].length <= 10 + 7. words[i] consists of lowercase English letters. + 8. All the strings of words are unique. + + Runtime: 6439 ms (Beats 26.38%) + Time Complexity: O(R * C * (4 ^ max L)) + - word의 최대 길이를 max L, words의 길이를 K라 하면, trie에 words를 모두 insert하는데 O(max L * K), upper bound + - board의 각 grid에서 조회하는데 O(R * C) + - grid마다 dfs 호출하는데, dfs의 방향은 4곳이고, 호출 스택의 최대 깊이는 max L 이므로, * O(4 ^ max L) + > O(max L * K) + O(R * C) * O(4 ^ max L) ~= O(R * C * (4 ^ max L)) + + Memory: 19.04 MB (Beats 20.79%) + Space Complexity: O(max L * K) + - trie의 공간 복잡도는 O(max L * K), upper bound + - board의 각 grid에서 dfs를 호출하고, dfs 호출 스택의 최대 깊이는 max L 이므로 O(max L) + - result의 최대 크기는 words의 길이와 같으므로 O(K), upper bound + > O(max L * K) + O(max L) + O(K) ~= O(max L * K) + """ + def solve_trie_dfs(self, board: List[List[str]], words: List[str]) -> List[str]: + MAX_R, MAX_C = len(board), len(board[0]) + DIRS = [(0, 1), (1, 0), (0, -1), (-1, 0)] + + trie = Trie() + for word in words: + trie.insert(word) + + def dfs(curr: Node, r: int, c: int, path: str): + nonlocal result + + if not (0 <= r < MAX_R and 0 <= c < MAX_C): + return + + if board[r][c] == "#": + return + + char = board[r][c] + if char not in curr.children: + return + + post = curr.children[char] + if post.data: + result.add(post.data) + + board[r][c] = "#" + for dir_r, dir_c in DIRS: + dfs(post, r + dir_r, c + dir_c, path + char) + board[r][c] = char + + result = set() + for r in range(MAX_R): + for c in range(MAX_C): + if board[r][c] in trie.root.children: + dfs(trie.root, r, c, "") + + return list(result) + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + board = [["o", "a", "a", "n"], ["e", "t", "a", "e"], ["i", "h", "k", "r"], ["i", "f", "l", "v"]] + words = ["oath","pea","eat","rain"] + output = ["eat","oath"] + self.assertEqual(Solution.findWords(Solution(), board, words), output) + + def test_2(self): + board = [["a","b"],["c","d"]] + words = ["abcb"] + output = [] + self.assertEqual(Solution.findWords(Solution(), board, words), output) + + +if __name__ == '__main__': + main() From 4479704ab5320c3cf8873349ba83bbb4a52def8a Mon Sep 17 00:00:00 2001 From: EGON Date: Thu, 14 Nov 2024 16:03:37 +0900 Subject: [PATCH 2/5] feat: solve #280 with python --- meeting-rooms-ii/EGON.py | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 meeting-rooms-ii/EGON.py diff --git a/meeting-rooms-ii/EGON.py b/meeting-rooms-ii/EGON.py new file mode 100644 index 000000000..56a76e27d --- /dev/null +++ b/meeting-rooms-ii/EGON.py @@ -0,0 +1,74 @@ +from typing import List +from unittest import TestCase, main + + +# Definition of Interval: +class Interval(object): + def __init__(self, start, end): + self.start = start + self.end = end + + +class Solution: + def minMeetingRooms(self, intervals: List[Interval]) -> int: + return self.solve_two_pointer(intervals) + + """ + LintCode 로그인이 안되어서 https://neetcode.io/problems/meeting-schedule-ii 에서 실행시키고 통과만 확인했습니다. + + Runtime: ? ms (Beats ?%) + Time Complexity: O(n log n) + - intervals의 길이를 n이라 하면, starts를 정렬하는데 O(n log n) + - ends를 정렬하는데 O(n log n) + - intervals를 인덱스를 이용해 전체 조회하는데 O(n) + > O(n log n) * 2 + O(n) ~= O(n log n) + + Memory: ? MB (Beats ?%) + Space Complexity: O(n) + - starts와 ends의 크기는 intervals와 같으므로 O(n) + - 포인터로 index를 사용했으므로 O(1) + > O(n) + O(1) ~= O(n) + """ + def solve_two_pointer(self, intervals: List[Interval]) -> int: + if not intervals: + return 0 + + starts, ends = sorted([i.start for i in intervals]), sorted([i.end for i in intervals]) + start_idx, end_idx = 0, 0 + schedule_count = 0 + while start_idx < len(intervals): + if starts[start_idx] < ends[end_idx]: + schedule_count += 1 + start_idx += 1 + else: + end_idx += 1 + start_idx += 1 + + return schedule_count + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + intervals = [Interval(0,40), Interval(5,10), Interval(15,20)] + output = 2 + self.assertEqual(Solution().minMeetingRooms(intervals), output) + + def test_2(self): + intervals = [Interval(4, 9)] + output = 1 + self.assertEqual(Solution().minMeetingRooms(intervals), output) + + def test_3(self): + intervals = [ + Interval(1, 5), + Interval(2, 6), + Interval(3, 7), + Interval(4, 8), + Interval(5, 9), + ] + output = 4 + self.assertEqual(Solution().minMeetingRooms(intervals), output) + + +if __name__ == '__main__': + main() From 18b6ffbec44db60b38edc760c33e956f965edb2b Mon Sep 17 00:00:00 2001 From: EGON Date: Thu, 14 Nov 2024 16:08:37 +0900 Subject: [PATCH 3/5] feat: solve #265 with python --- house-robber-ii/EGON.py | 60 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 house-robber-ii/EGON.py diff --git a/house-robber-ii/EGON.py b/house-robber-ii/EGON.py new file mode 100644 index 000000000..8f69208b0 --- /dev/null +++ b/house-robber-ii/EGON.py @@ -0,0 +1,60 @@ +from collections import deque +from typing import List +from unittest import TestCase, main + + +class Solution: + def rob(self, nums: List[int]) -> int: + return self.solve_dp(nums) + + """ + Runtime: 0 ms (Beats 100.00%) + Time Complexity: O(n) + - 인덱스가 0인 곳을 도둑질한 경우에 대한 dp1에서, 인덱스 2부터 n-2까지 조회하므로 O(n - 3) + - 각 조회마다 2항 max 연산을 2회씩 하므로 * O(2 * 2) + - 인덱스가 0인 곳을 도둑질하지 않는 경우에 대한 dp2에서, 인덱스 2부터 n-1까지 조회하므로 O(n - 2) + - 각 조회마다 2항 max 연산을 2회씩 하므로 * O(2 * 2) + - 그 외에 정해진 횟수의 max 연산들은 무시, O(C) + > O(n - 3) * O(2 * 2) + O(n - 4) * O(2 * 2) + O(C) ~= O(n) * O(4) ~= O(n) + + Memory: 16.59 (Beats 62.16%) + Space Complexity: O(n) + - dp1과 dp2가 각각 nums의 길이와 같으므로 O(n * 2) + > O(n * 2) ~= O(n) + """ + def solve_dp(self, nums: List[int]) -> int: + if len(nums) <= 3: + return max(nums) + + dp1 = [0] * len(nums) + dp1[0], dp1[1] = nums[0], max(nums[0], nums[1]) + max_dp1 = max(dp1[0], dp1[1]) + for i in range(2, len(nums) - 1): + dp1[i] = max(dp1[i - 1], dp1[i - 2] + nums[i]) + max_dp1 = max(max_dp1, dp1[i]) + + dp2 = [0] * len(nums) + dp2[0], dp2[1] = 0, nums[1] + max_dp2 = max(dp2[0], dp2[1]) + for i in range(2, len(nums)): + dp2[i] = max(dp2[i - 1], dp2[i - 2] + nums[i]) + max_dp2 = max(max_dp2, dp2[i]) + + return max(max_dp1, max_dp2) + + +class _LeetCodeTestCases(TestCase): + + def test_1(self): + nums = [2, 3, 2] + output = 3 + self.assertEqual(Solution.rob(Solution(), nums), output) + + def test_2(self): + nums = [1, 2, 3, 1] + output = 4 + self.assertEqual(Solution.rob(Solution(), nums), output) + + +if __name__ == '__main__': + main() From fe5d3cac46a223a792117fd7fe9a7fa25c0b29da Mon Sep 17 00:00:00 2001 From: EGON Date: Thu, 14 Nov 2024 16:11:38 +0900 Subject: [PATCH 4/5] feat: solve #250 with python --- binary-tree-level-order-traversal/EGON.py | 108 ++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 binary-tree-level-order-traversal/EGON.py diff --git a/binary-tree-level-order-traversal/EGON.py b/binary-tree-level-order-traversal/EGON.py new file mode 100644 index 000000000..765371780 --- /dev/null +++ b/binary-tree-level-order-traversal/EGON.py @@ -0,0 +1,108 @@ +from collections import deque +from typing import Optional, List +from unittest import TestCase, main + + +# Definition for a binary tree node. +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + + +class Solution: + def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]: + return self.solve_dfs(root) + + """ + Runtime: 0 ms (Beats 100.00%) + Time Complexity: O(n) + > 각 node를 bfs 방식으로 한 번 씩 조회하므로 O(n) + + Memory: 17.42 (Beats 11.96%) + Space Complexity: O(n) + > 최악의 경우, deque에 최대 node의 갯수만큼 저장될 수 있으므로 O(n), upper bound + """ + def solve_bfs(self, root: Optional[TreeNode]) -> List[List[int]]: + if not root: + return [] + + dq = deque([root]) + result = [] + while dq: + tmp_result = [] + for _ in range(len(dq)): + curr = dq.popleft() + tmp_result.append(curr.val) + + if curr.left: + dq.append(curr.left) + if curr.right: + dq.append(curr.right) + + result.append(tmp_result) + + return result + + """ + Runtime: 1 ms (Beats 38.71%) + Time Complexity: O(n) + > 각 node를 dfs 방식으로 한 번 씩 조회하므로 O(n) + + Memory: 17.49 (Beats 11.96%) + Space Complexity: O(1) + > 최악의 경우, list에 최대 node의 갯수만큼 저장될 수 있으므로 O(n), upper bound + """ + def solve_dfs(self, root: Optional[TreeNode]) -> List[List[int]]: + if not root: + return [] + + def dfs(node: TreeNode, depth: int): + if len(result) <= depth: + result.append([node.val]) + else: + result[depth].append(node.val) + + if node.left: + dfs(node.left, depth + 1) + if node.right: + dfs(node.right, depth + 1) + + result = [] + dfs(root, 0) + + return result + + +class _LeetCodeTestCases(TestCase): + + def test_1(self): + root = TreeNode(3) + node1 = TreeNode(9) + node2 = TreeNode(20) + node3 = TreeNode(15) + node4 = TreeNode(7) + root.left = node1 + root.right = node2 + node2.left = node3 + node2.right = node4 + output = [[3], [9, 20], [15, 7]] + self.assertEqual(Solution.levelOrder(Solution(), root), output) + + def test_2(self): + root = TreeNode(1) + node1 = TreeNode(2) + node2 = TreeNode(3) + node3 = TreeNode(4) + node4 = TreeNode(5) + root.left = node1 + root.right = node2 + node1.left = node3 + node2.left = node4 + output = [[1], [2, 3], [4, 5]] + self.assertEqual(Solution.levelOrder(Solution(), root), output) + + +if __name__ == '__main__': + main() From d0ebb696d2e13455ef5eba9dec96a8d10f3cd77a Mon Sep 17 00:00:00 2001 From: EGON Date: Thu, 14 Nov 2024 16:16:06 +0900 Subject: [PATCH 5/5] feat: solve #234 with python --- reverse-bits/EGON.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 reverse-bits/EGON.py diff --git a/reverse-bits/EGON.py b/reverse-bits/EGON.py new file mode 100644 index 000000000..719429da9 --- /dev/null +++ b/reverse-bits/EGON.py @@ -0,0 +1,34 @@ +from unittest import TestCase, main + + +class Solution: + def reverseBits(self, n: int) -> int: + return self.solve(n) + + """ + Runtime: 32 ms (Beats 80.50%) + Time Complexity: O(1) + - n을 str로 변환하는데, n은 32 bit 정수이므로 O(32), upper bound + - zfill로 문자열의 길이를 32로 맞추는데, O(32), upper bound + - 문자열을 뒤집는데 마찬가지로, O(32), upper bound + - 뒤집은 문자열을 정수로 변환하는데 문자열에 비례하며 이 길이는 최대 32이므로, O(32), upper bound + > O(32) * O(32) * O(32) * O(32) ~= O(1) + + Memory: 16.50 (Beats 64.72%) + Space Complexity: O(1) + - 각 단계마다 최대 길이가 32인 문자열이 임시로 저장되므로 O(32) * 4 + > O(32) * 4 ~= O(1) + """ + def solve(self, n: int) -> int: + return int(str(n).zfill(32)[::-1], 2) + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + n = int("00000010100101000001111010011100") + output = 964176192 + self.assertEqual(Solution.reverseBits(Solution(), n), output) + + +if __name__ == '__main__': + main()