Skip to content

[Helena] Week 11 #1043

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions binary-tree-maximum-path-sum/yolophg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Time Complexity: O(N) - visit each node once.
# Space Complexity: O(H) - recursive call stack, where H is the tree height.
# - O(log N) for balanced trees, O(N) for skewed trees.

class Solution:
def maxPathSum(self, root: Optional[TreeNode]) -> int:
def dfs(node):
nonlocal ans
if not node:
return 0

# get the max path sum from left and right subtrees (ignore negatives)
left = max(dfs(node.left), 0)
right = max(dfs(node.right), 0)

# update the global max path sum including this node
ans = max(ans, left + right + node.val)

# return the max path sum that can be extended to the parent
return max(left, right) + node.val

# initialize with the smallest possible value
ans = float('-inf')
# start DFS from the root
dfs(root)
return ans
30 changes: 30 additions & 0 deletions graph-valid-tree/yolophg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Time Complexity: O(N) - iterate through all edges and nodes at most once.
# Space Complexity: O(N) - store the graph as an adjacency list and track visited nodes.

class Solution:
def valid_tree(self, n: int, edges: List[List[int]]) -> bool:
# a tree with 'n' nodes must have exactly 'n-1' edges
if len(edges) != n - 1:
return False

# build an adjacency list (graph representation)
graph = {i: [] for i in range(n)}
for u, v in edges:
graph[u].append(v)
graph[v].append(u)

# use BFS to check if the graph is fully connected and acyclic
visited = set()
queue = [0]
visited.add(0)

while queue:
node = queue.pop(0)
for neighbor in graph[node]:
if neighbor in visited:
continue
visited.add(neighbor)
queue.append(neighbor)

# if we visited all nodes, it's a valid tree
return len(visited) == n
14 changes: 14 additions & 0 deletions maximum-depth-of-binary-tree/yolophg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Time Complexity: O(N) - visit each node once.
# Space Complexity: O(H) - the recursion stack goes as deep as the height of the tree.
# - Worst case (skewed tree): O(N)
# - Best case (balanced tree): O(log N)

class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
# if there's no node, the depth is just 0.
if not root:
return 0

# recursively get the depth of left and right subtrees
# then add 1 for the current node
return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))
27 changes: 27 additions & 0 deletions merge-intervals/yolophg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Time Complexity: O(N log N) - sorting takes O(N log N), and merging takes O(N)
# Space Complexity: O(N) - store the merged intervals in a new list.

class Solution:

def merge(self, intervals: List[List[int]]) -> List[List[int]]:
# sort the intervals by their start values
intervals.sort(key=lambda x: x[0])

# this will store our final merged intervals
merged = []
# start with the first interval
prev = intervals[0]

# iterate through the sorted intervals
for interval in intervals[1:]:
if interval[0] <= prev[1]:
# overlapping intervals → merge them by updating 'end' value
prev[1] = max(prev[1], interval[1])
else:
# no overlap → add 'prev' to the merged list and update 'prev'
merged.append(prev)
prev = interval

merged.append(prev)

return merged
34 changes: 34 additions & 0 deletions reorder-list/yolophg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Time Complexity: O(N) - traverse the list three times:
# (1) find the middle (O(N)),
# (2) reverse the second half (O(N)),
# (3) merge the two halves (O(N)).
# Space Complexity: O(1) - use a few extra pointers, no additional data structures.

class Solution:
def reorderList(self, head: Optional[ListNode]) -> None:
# find the middle of the list using slow & fast pointers
slow, fast = head, head.next
while fast and fast.next:
slow = slow.next
fast = fast.next.next

# reverse the second half of the list
second = slow.next
# cut the list into two halves
slow.next = None
prev = None

while second:
temp = second.next
second.next = prev
prev = second
second = temp

# merge the two halves (alternating nodes)
first, second = head, prev

while second:
temp1, temp2 = first.next, second.next
first.next = second
second.next = temp1
first, second = temp1, temp2