From beded946b9240d379f97f68a18cc64f7b9128311 Mon Sep 17 00:00:00 2001 From: Dusuna <94776135+dusunax@users.noreply.github.com> Date: Mon, 17 Feb 2025 15:55:22 +0900 Subject: [PATCH 1/4] add solution: maximum-depth-of-binary-tree --- maximum-depth-of-binary-tree/dusunax.py | 38 +++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 maximum-depth-of-binary-tree/dusunax.py diff --git a/maximum-depth-of-binary-tree/dusunax.py b/maximum-depth-of-binary-tree/dusunax.py new file mode 100644 index 000000000..17433a649 --- /dev/null +++ b/maximum-depth-of-binary-tree/dusunax.py @@ -0,0 +1,38 @@ +''' +# 104. Maximum Depth of Binary Tree + +use DFS to find the maximum depth of the binary tree. + +``` +helper function explanation: +- store the max_depth in the nonlocal variable.(outside of the helper function) +- base case: if the node is None, update the max_depth and return. +- in the helper function, do recursive call for the left and right children of the node. + - update the count for the depth of the tree. +- update the max_depth when the node is a leaf node's children. +``` + +## TC is O(n) + +visit each node once for checking if it is a leaf node's children. + +## SC is O(h) + +h for height of the tree +''' +class Solution: + def maxDepth(self, root: Optional[TreeNode]) -> int: + max_depth = 0 + + def helper(node, count): + nonlocal max_depth + if node is None: + max_depth = max(max_depth, count) + return + + helper(node.left, count+1) + helper(node.right, count + 1) + + helper(root, max_depth) + + return max_depth From bf498a944b1d0d92838e7ed91b5759e8d6c8ca23 Mon Sep 17 00:00:00 2001 From: Dusuna <94776135+dusunax@users.noreply.github.com> Date: Mon, 17 Feb 2025 16:15:38 +0900 Subject: [PATCH 2/4] update solution: maximum-depth-of-binary-tree --- maximum-depth-of-binary-tree/dusunax.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/maximum-depth-of-binary-tree/dusunax.py b/maximum-depth-of-binary-tree/dusunax.py index 17433a649..e1c80a2a4 100644 --- a/maximum-depth-of-binary-tree/dusunax.py +++ b/maximum-depth-of-binary-tree/dusunax.py @@ -3,6 +3,7 @@ use DFS to find the maximum depth of the binary tree. +## A. if we use a helper function (not a good idea) ``` helper function explanation: - store the max_depth in the nonlocal variable.(outside of the helper function) @@ -12,6 +13,11 @@ - update the max_depth when the node is a leaf node's children. ``` +## B. return the max_depth directly +👉 why helper function is not necessary? +recursion function can return the max_depth directly. +remove side effect & non-local variable. + ## TC is O(n) visit each node once for checking if it is a leaf node's children. @@ -21,7 +27,10 @@ h for height of the tree ''' class Solution: - def maxDepth(self, root: Optional[TreeNode]) -> int: + ''' + A. first approach with side effect + ''' + def maxDepthWithHelper(self, root: Optional[TreeNode]) -> int: max_depth = 0 def helper(node, count): @@ -36,3 +45,17 @@ def helper(node, count): helper(root, max_depth) return max_depth + + ''' + B. return the max_depth directly. + - more concise & readable + - no side effect & non-local variable + ''' + def maxDepth(self, root: Optional[TreeNode]) -> int: + if root is None: + return 0 + + left_count = self.maxDepth(root.left) + right_count = self.maxDepth(root.right) + + return max(left_count, right_count) + 1 From 5180d3996e0e3595d17052afcc313a2fc95f8847 Mon Sep 17 00:00:00 2001 From: Dusuna <94776135+dusunax@users.noreply.github.com> Date: Mon, 17 Feb 2025 18:20:18 +0900 Subject: [PATCH 3/4] add solution: reorder-list --- reorder-list/dusunax.py | 49 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 reorder-list/dusunax.py diff --git a/reorder-list/dusunax.py b/reorder-list/dusunax.py new file mode 100644 index 000000000..e372d2a38 --- /dev/null +++ b/reorder-list/dusunax.py @@ -0,0 +1,49 @@ +''' +# 143. Reorder list +use two pointers for each steps. + +1. finding the middle + - two pointers: slow, fast + - move slow 1, fast 2 until fast reaches the end. +2. reversing the second half + - two pointers: prev, curr + - start from slow to end, do common reverse linked list operation. + - need to break the links to halves beforehand. +3. merging first & second + - two pointers: frist, second + - merge second between first, until second is None + +## TC is O(n) +- find the middle: O(n) +- reverse the second half: O(n) +- merge the two halves: O(n) + +## SC is O(1) +- no extra space is used. +''' +class Solution: + def reorderList(self, head: Optional[ListNode]) -> None: + # 1. finding the middle + slow, fast = head, head + while fast and fast.next: + slow = slow.next + fast = fast.next.next + + # 2. reversing second half + second_not_reversed = slow.next + slow.next = None + prev, curr = None, second_not_reversed + while curr: + temp = curr.next + curr.next = prev + prev = curr + curr = temp + + # 3. merging first & second + first, second = head, prev + while second: + temp1, temp2 = first.next, second.next + first.next = second + second.next = temp1 + first = temp1 + second = temp2 From ef969af2a38750396433a80023164777f41f0494 Mon Sep 17 00:00:00 2001 From: Dusuna <94776135+dusunax@users.noreply.github.com> Date: Fri, 21 Feb 2025 13:04:47 +0900 Subject: [PATCH 4/4] add solution: graph-valid-tree --- graph-valid-tree/dusunax.py | 67 +++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 graph-valid-tree/dusunax.py diff --git a/graph-valid-tree/dusunax.py b/graph-valid-tree/dusunax.py new file mode 100644 index 000000000..7f4581c61 --- /dev/null +++ b/graph-valid-tree/dusunax.py @@ -0,0 +1,67 @@ +''' +# 261. Graph Valid Tree + +## What constitutes a 🌲 +1. it's a graph. +2. Connected: edges == n - 1, visited node count == n +3. Acyclic: there is no cycle. + +## Approach A. DFS +use DFS to check if there is a cycle in the graph. +- if there were no cycle & visited node count == n, return True. + +## Approach B. Disjoint Set Union (서로소 집합) +use Disjoint Set Union to check if there is a cycle in the graph. +- if you find a cycle, return False immediately. +- if you find no cycle, return True. + +### Union Find Operation +- Find: find the root of a node. + - if the root of two nodes is already the same, there is a cycle. +- Union: connect two nodes. + +## Approach Comparison +- **A. DFS**: simple and easy to understand. +- **B. Disjoint Set Union**: quicker to check if there is a cycle. if there were more edges, Union Find would be faster. +''' +class Solution: + def validTreeDFS(self, n: int, edges: List[List[int]]) -> bool: + if len(edges) != n - 1: + return False + + graph = [[] for _ in range(n)] + for node, neighbor in edges: + graph[node].append(neighbor) + graph[neighbor].append(node) + + visited = set() + def dfs(node): + visited.add(node) + for neighbor in graph[node]: + if neighbor not in visited: + dfs(neighbor) + + dfs(0) + return len(visited) == n + + def validTreeUnionFind(self, n: int, edges: List[List[int]]) -> bool: + if len(edges) != n - 1: + return False + + parent = [i for i in range(n)] + + def find(x): + if x == parent[x]: + return x + parent[x] = find(parent[x]) + return parent[x] + + def union(x, y): + parent[find(x)] = find(y) + + for node, neighbor in edges: + if find(node) == find(neighbor): + return False + union(node, neighbor) + + return True