Skip to content

Commit 4e8e47f

Browse files
committed
feat: trees working
1 parent 985746d commit 4e8e47f

10 files changed

Lines changed: 281 additions & 11 deletions

technical-fundamentals/python/coding/problems/30_trees.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,40 @@ def __init__(
2121

2222

2323
class Tree(Generic[T]):
24+
def backtrack(self, node, answer):
25+
if not node:
26+
return answer
27+
28+
to_track = []
29+
for n in [node.left, node.right]:
30+
if n:
31+
answer.append(n)
32+
to_track.append(n)
33+
34+
for n in to_track:
35+
self.backtrack(n, answer)
36+
37+
return answer
38+
2439
def bfs(
2540
self,
2641
node: Optional[TreeNode[T]],
2742
visit: Callable[[TreeNode[T]], None],
2843
) -> None:
29-
pass
44+
if node:
45+
nodes = []
46+
nodes.append(node)
47+
self.backtrack(node, nodes)
48+
while nodes:
49+
visit(nodes.pop(0))
3050

3151
def dfs(
3252
self,
3353
node: Optional[TreeNode[T]],
3454
visit: Callable[[TreeNode[T]], None],
3555
) -> None:
36-
pass
56+
if node:
57+
visit(node)
58+
self.dfs(node.left, visit)
59+
self.dfs(node.right, visit)
60+

technical-fundamentals/python/coding/problems/31_has_route_between_nodes.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@ def __init__(self, value: int, neighbors: List["GraphNode"] = None):
1111
self.value = value
1212
self.neighbors: List["GraphNode"] = neighbors if neighbors is not None else []
1313

14+
def backtrack(start, end, path):
15+
if start == end:
16+
return True
17+
18+
if not start or not end:
19+
return False
20+
21+
for n in start.neighbors:
22+
if n not in path:
23+
path.append(n)
24+
if backtrack(n, end, path):
25+
return True
26+
27+
return False
1428

1529
def has_route_between_nodes(start: GraphNode, end: GraphNode) -> bool:
16-
pass
30+
return backtrack(start, end, [])

technical-fundamentals/python/coding/problems/32_minimal_tree.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,12 @@ def __init__(
3030

3131

3232
def minimal_tree(sorted_array: List[T]) -> Optional[TreeNode[T]]:
33-
pass
33+
if not sorted_array:
34+
return None
35+
36+
len_array = len(sorted_array)
37+
middle = len_array // 2
38+
root = TreeNode(sorted_array[middle])
39+
root.left = minimal_tree(sorted_array[0:middle])
40+
root.right = minimal_tree(sorted_array[middle+1:])
41+
return root

technical-fundamentals/python/coding/problems/33_list_of_depths.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,42 @@ def __init__(self, value: T, next: Optional["ListNode[T]"] = None):
2626
self.next = next
2727

2828

29+
30+
def dfs(node, depth, answer):
31+
if not node:
32+
return answer
33+
34+
len_answer = len(answer)
35+
to_traverse = []
36+
for n in [node.left, node.right]:
37+
if n:
38+
if depth == len_answer:
39+
answer.append([])
40+
answer[depth].append(n.value)
41+
to_traverse.append(n)
42+
43+
for n in to_traverse:
44+
dfs(n, depth+1, answer)
45+
46+
return answer
47+
2948
def list_of_depths(root: Optional[TreeNode[T]]) -> List[ListNode[T]]:
30-
pass
49+
if not root:
50+
return []
51+
52+
answer = []
53+
54+
answer.append([root.value])
55+
dfs(root, 1, answer)
56+
57+
returned = []
58+
for a in answer:
59+
dummy = ListNode(0)
60+
pointer = dummy
61+
for x in a:
62+
n = ListNode(x)
63+
pointer.next = n
64+
pointer = pointer.next
65+
returned.append(dummy.next)
66+
67+
return returned

technical-fundamentals/python/coding/problems/34_check_balanced.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,20 @@ def __init__(
2020
self.left = left
2121
self.right = right
2222

23+
def check_length(tree: Optional[TreeNode[T]]) -> bool:
24+
if not tree:
25+
return 0
26+
27+
return max([
28+
check_length(tree.left),
29+
check_length(tree.right)
30+
]) + 1
2331

2432
def check_balanced(tree: Optional[TreeNode[T]]) -> bool:
25-
pass
33+
if not tree:
34+
return True
35+
36+
left = check_length(tree.left)
37+
right = check_length(tree.right)
38+
39+
return abs(left-right) <= 1

technical-fundamentals/python/coding/problems/35_validate_bst.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,30 @@ def __init__(
1818
self.left = left
1919
self.right = right
2020

21+
def max_tree(node: Optional[TreeNode[T]]) -> int | None:
22+
if not node:
23+
return None
24+
25+
to_check = [node.value]
26+
max_left = max_tree(node.left)
27+
if max_left is not None:
28+
to_check.append(max_left)
29+
max_right = max_tree(node.right)
30+
if max_right is not None:
31+
to_check.append(max_right)
32+
return max(
33+
to_check
34+
)
35+
2136

2237
def validate_bst(node: Optional[TreeNode[T]]) -> bool:
23-
pass
38+
if not node:
39+
return True
40+
41+
max_left = max_tree(node.left)
42+
max_right = max_tree(node.right)
43+
44+
return (
45+
(max_left is None or max_left <= node.value ) and
46+
(max_right is None or max_right >= node.value)
47+
)

technical-fundamentals/python/coding/problems/36_successor.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,24 @@ def __init__(
2121
self.right = right
2222
self.parent = parent
2323

24+
def min_node(node: TreeNode[T]) -> Optional[TreeNode[T]]:
25+
if not node or not node.left:
26+
return node
27+
28+
return min_node(node.left)
2429

2530
def successor(node: TreeNode[T]) -> Optional[TreeNode[T]]:
26-
pass
31+
if not node:
32+
return None
33+
34+
if node.right is None:
35+
if not node.parent:
36+
return None
37+
38+
pointer = node.parent
39+
while pointer and pointer.value < node.value:
40+
pointer = pointer.parent
41+
42+
return pointer
43+
44+
return min_node(node.right)

technical-fundamentals/python/coding/problems/37_build_order.py

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,84 @@
99
# projects: a, b, c, d, e, f
1010
# dependencies: (a, d), (f, b), (b, d), (f, a), (d, c)
1111
# Output: e, f, a, b, d, c
12+
#
13+
# -> a -> f
14+
# dummy -> c -> d -> b -> f
15+
# -> e
16+
# -> d
17+
# -> b
18+
# -> a
19+
# -> f
20+
#
21+
# path c
22+
# path d
23+
# path a
24+
# path f
25+
# append f
26+
# pop f
27+
# append a
28+
# pop a
29+
# path b
30+
# append b
31+
# pop b
32+
# append d
33+
# pop d
34+
# append c
35+
# pop c
36+
# append e
37+
1238

1339
from typing import List, Union
1440

41+
class GraphNode:
42+
def __init__(self, value: str, neighbors: List["GraphNode"] = None):
43+
self.value = value
44+
self.neighbors: List["GraphNode"] = neighbors if neighbors is not None else []
45+
46+
def dfs(node, answer, path):
47+
if not node:
48+
return answer
49+
50+
for n in node.neighbors:
51+
if n.value not in path and n.value not in answer:
52+
print('path', n.value)
53+
path.append(n.value)
54+
dfs(n, answer, path)
55+
print('pop', n.value)
56+
path.pop()
57+
answer.append(node.value)
58+
print('append', node.value)
59+
return answer
60+
1561

1662
def build_order(
1763
projects: List[str], dependencies: List[List[str]]
1864
) -> Union[List[str], str]:
19-
pass
65+
hashmap = {}
66+
starts = {}
67+
if not projects and not dependencies:
68+
return []
69+
70+
for a in projects:
71+
n = GraphNode(a)
72+
hashmap[a] = n
73+
starts[a] = n
74+
75+
for left, right in dependencies:
76+
if right not in hashmap or left not in hashmap:
77+
raise Exception("No valid build order exists")
78+
hashmap[right].neighbors.append(hashmap[left])
79+
if left in starts:
80+
del starts[left]
81+
82+
if not starts:
83+
raise Exception("No valid build order exists")
84+
85+
dummy = GraphNode('')
86+
for n in list(starts.values())[::-1]:
87+
dummy.neighbors.append(n)
88+
89+
answer = dfs(dummy, [], [])
90+
print(answer[:-1])
91+
return [x for x in answer[:-1]]
92+

technical-fundamentals/python/coding/problems/38_first_common_ancestor.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,30 @@ def __init__(
2121
self.right = right
2222

2323

24+
def find(node, q, path):
25+
if node is None:
26+
return None
27+
28+
if node is q:
29+
return path
30+
31+
for n in [node.left, node.right]:
32+
if n:
33+
path.append(n)
34+
if find(n, q, path):
35+
return path
36+
path.pop()
37+
38+
2439
def first_common_ancestor(
2540
root: Optional[TreeNode[T]],
2641
p: TreeNode[T],
2742
q: TreeNode[T],
2843
) -> Optional[TreeNode[T]]:
29-
pass
44+
answer = find(root, p, [root])
45+
while answer:
46+
node = answer.pop()
47+
if find(node, q, []):
48+
return node
49+
50+

technical-fundamentals/python/coding/problems/39_bst_sequences.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@
1515

1616
T = TypeVar("T")
1717

18+
# 5
19+
# 3 7
20+
# 2 4 6 8
21+
22+
23+
# root = TreeNode(5,
24+
# left=TreeNode(3, left=TreeNode(2), right=TreeNode(4)),
25+
# right=TreeNode(7, left=TreeNode(6), right=TreeNode(8)),
26+
# )
1827

1928
class TreeNode(Generic[T]):
2029
def __init__(
@@ -27,6 +36,34 @@ def __init__(
2736
self.left = left
2837
self.right = right
2938

39+
def total_nodes(root: TreeNode[T] | None):
40+
if not root:
41+
return 0
42+
43+
return total_nodes(root.left) + total_nodes(root.right) + 1
44+
45+
46+
def backtrack(total, choices, path, answer):
47+
if len(path) == total:
48+
answer.append(list(path))
49+
return answer
50+
51+
for i in range(len(choices)):
52+
c = choices[i]
53+
if c.value not in path:
54+
path.append(c.value)
55+
new_choices = choices[:i] + choices[i+1:]
56+
if c.left:
57+
new_choices.append(c.left)
58+
if c.right:
59+
new_choices.append(c.right)
60+
61+
backtrack(total, new_choices, path, answer)
62+
path.pop()
63+
64+
return answer
3065

3166
def bst_sequences(root: TreeNode[T]) -> List[List[T]]:
32-
pass
67+
total = total_nodes(root)
68+
return backtrack(total, [root], [], [])
69+

0 commit comments

Comments
 (0)