Skip to content

Commit f0f8b4d

Browse files
authored
Merge pull request DaleStudy#130 from bhyun-kim/main
[bhyun-kim.py, ๊น€๋ณ‘ํ˜„] Week 7 Solutions
2 parents 528e73a + 2f00241 commit f0f8b4d

File tree

5 files changed

+326
-0
lines changed

5 files changed

+326
-0
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
"""
2+
102. Binary Tree Level Order Traversal
3+
https://leetcode.com/problems/binary-tree-level-order-traversal/
4+
"""
5+
6+
from typing import List, Optional
7+
8+
9+
# Definition for a binary tree node.
10+
class TreeNode:
11+
def __init__(self, val=0, left=None, right=None):
12+
self.val = val
13+
self.left = left
14+
self.right = right
15+
16+
17+
"""
18+
Solution
19+
Breadth First Search (BFS) using Queue
20+
21+
The problem is asking to return the node values at each level of the binary tree.
22+
To solve this problem, we can use BFS algorithm with a queue.
23+
We will traverse the tree level by level and store the node values at each level.
24+
25+
1. Initialize an empty list to store the output.
26+
2. Initialize an empty queue.
27+
3. Add the root node to the queue.
28+
4. While the queue is not empty, do the following:
29+
- Get the size of the queue to know the number of nodes at the current level.
30+
- Initialize an empty list to store the node values at the current level.
31+
- Traverse the nodes at the current level and add the node values to the list.
32+
- If the node has left or right child, add them to the queue.
33+
- Decrease the level size by 1.
34+
- Add the list of node values at the current level to the output.
35+
5. Return the output.
36+
37+
Time complexity: O(N)
38+
- We visit each node once
39+
40+
Space complexity: O(N)
41+
- The maximum number of nodes in the queue is the number of nodes at the last level
42+
- The maximum number of nodes at the last level is N/2
43+
- The output list stores the node values at each level which is N
44+
- Thus, the space complexity is O(N)
45+
46+
"""
47+
48+
49+
class Solution:
50+
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
51+
if root is None:
52+
return
53+
output = []
54+
queue = []
55+
queue.append(root)
56+
57+
while len(queue) > 0:
58+
level_size = len(queue)
59+
level_output = []
60+
61+
while level_size > 0:
62+
node = queue.pop(0)
63+
level_output.append(node.val)
64+
65+
if node.left is not None:
66+
queue.append(node.left)
67+
if node.right is not None:
68+
queue.append(node.right)
69+
70+
level_size -= 1
71+
72+
output.append(level_output)
73+
74+
return output
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
235. Lowest Common Ancestor of a Binary Search Tree
3+
https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/
4+
"""
5+
6+
7+
# Definition for a binary tree node.
8+
class TreeNode:
9+
def __init__(self, x):
10+
self.val = x
11+
self.left = None
12+
self.right = None
13+
14+
15+
"""
16+
Solution:
17+
- If both p and q are greater than the root, the lowest common ancestor is in the right subtree.
18+
- If both p and q are less than the root, the lowest common ancestor is in the left subtree.
19+
- Otherwise, the root is the lowest common ancestor.
20+
21+
Time complexity: O(N)
22+
- The function is called recursively for each node
23+
Space complexity: O(N)
24+
- Maximum depth of the recursion is the height of the tree
25+
"""
26+
27+
28+
class Solution:
29+
def lowestCommonAncestor(
30+
self, root: "TreeNode", p: "TreeNode", q: "TreeNode"
31+
) -> "TreeNode":
32+
if p.val > root.val and q.val > root.val:
33+
return self.lowestCommonAncestor(root.right, p, q)
34+
35+
elif p.val < root.val and q.val < root.val:
36+
return self.lowestCommonAncestor(root.left, p, q)
37+
else:
38+
return root
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
"""
2+
19. Remove Nth Node From End of List
3+
https://leetcode.com/problems/remove-nth-node-from-end-of-list/
4+
"""
5+
6+
7+
from typing import Optional
8+
9+
10+
class ListNode:
11+
def __init__(self, val=0, next=None):
12+
self.val = val
13+
self.next = next
14+
15+
16+
"""
17+
Solution 1:
18+
Two Pass Algorithm 1
19+
- First pass: Count the number of nodes and store the values in the list
20+
- Second pass: Build the new list without the Nth node from the end
21+
22+
Time complexity: O(N)
23+
- Two passes are required
24+
Space complexity: O(N)
25+
- The list stores the values of the nodes
26+
- The new nodes are created to build the new list
27+
"""
28+
29+
30+
class Solution1:
31+
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
32+
vals = []
33+
34+
while head:
35+
vals.append(head.val)
36+
head = head.next
37+
38+
dummy_node = ListNode()
39+
tail = dummy_node
40+
idx_to_remove = len(vals) - n
41+
vals = vals[:idx_to_remove] + vals[idx_to_remove + 1 :]
42+
43+
for v in vals:
44+
tail.next = ListNode(val=v)
45+
tail = tail.next
46+
47+
return dummy_node.next
48+
49+
50+
"""
51+
Solution 2:
52+
Reference:
53+
[1] https://leetcode.com/problems/remove-nth-node-from-end-of-list/editorial/
54+
[2] https://www.algodale.com/problems/remove-nth-node-from-end-of-list/
55+
One Pass Algorithm
56+
- Use two pointers to maintain a gap of n nodes between them
57+
- When the first pointer reaches the end, the second pointer will be at the Nth node from the end
58+
59+
Time complexity: O(N)
60+
- Only one pass is required
61+
Space complexity: O(1)
62+
- No extra space is required
63+
"""
64+
65+
66+
class Solution2:
67+
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
68+
dummy = ListNode()
69+
dummy.next = head
70+
first = dummy
71+
second = dummy
72+
73+
for _ in range(n + 1):
74+
first = first.next
75+
76+
while first:
77+
first = first.next
78+
second = second.next
79+
80+
second.next = second.next.next
81+
82+
return dummy.next

โ€Žreorder-list/bhyun-kim.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
"""
2+
143. Reorder List
3+
https://leetcode.com/problems/reorder-list/
4+
"""
5+
6+
from typing import Optional
7+
8+
9+
class ListNode:
10+
def __init__(self, val=0, next=None):
11+
self.val = val
12+
self.next = next
13+
14+
15+
"""
16+
Solution:
17+
To reorder the linked list, we can follow these steps:
18+
First, find the middle of the linked list using the slow and fast pointers.
19+
Reverse the second half of the linked list.
20+
Merge the first half and the reversed second half.
21+
22+
1. Find the middle of the linked list using the slow and fast pointers
23+
- Initialize the slow and fast pointers to the head of the linked list
24+
- Move the slow pointer by one step and the fast pointer by two steps
25+
until the fast pointer reaches the end of the linked list.
26+
2. Reverse the second half of the linked list
27+
- Initialize the prev and curr pointers to None and the middle node, respectively
28+
- Iterate through the second half of the linked list
29+
- Store the next node of the current node
30+
- Reverse the current node
31+
- Move the prev and curr pointers to the next nodes
32+
3. Merge the first half and the reversed second half
33+
- Initialize the first and second pointers to the head and the reversed second half, respectively
34+
- Iterate through the linked list
35+
- Store the next nodes of the first and second pointers
36+
- Update the next pointers of the first and second pointers
37+
- Move the first and second pointers to the next nodes
38+
39+
Time complexity: O(N)
40+
- We iterate through the linked list to find the middle node and reverse the second half
41+
- The time complexity is O(N)
42+
43+
Space complexity: O(1)
44+
- We only use constant extra space for the pointers
45+
- The space complexity is O(1)
46+
47+
"""
48+
49+
50+
class Solution:
51+
def reorderList(self, head: Optional[ListNode]) -> None:
52+
"""
53+
Do not return anything, modify head in-place instead.
54+
"""
55+
if not head or not head.next:
56+
return
57+
58+
slow, fast = head, head
59+
while fast and fast.next:
60+
slow = slow.next
61+
fast = fast.next.next
62+
63+
prev, curr = None, slow
64+
while curr:
65+
next_temp = curr.next
66+
curr.next = prev
67+
prev = curr
68+
curr = next_temp
69+
70+
first, second = head, prev
71+
while second.next:
72+
tmp1, tmp2 = first.next, second.next
73+
first.next = second
74+
second.next = tmp1
75+
first, second = tmp1, tmp2
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""
2+
98. Validate Binary Search Tree
3+
https://leetcode.com/problems/validate-binary-search-tree/
4+
5+
6+
"""
7+
from typing import Optional
8+
9+
10+
class TreeNode:
11+
def __init__(self, val=0, left=None, right=None):
12+
self.val = val
13+
self.left = left
14+
self.right = right
15+
16+
17+
"""
18+
Solution1:
19+
Recursion
20+
In the given problem, the subtree of a node has a range of values according to the previous nodes.
21+
Thus, we can define a function that checks the validity of the subtree of a node with the range of values.
22+
23+
- Define a function that checks the validity of the subtree of a node with the range of values
24+
- Check the validity of the left subtree and the right subtree
25+
- with the range of values that the left subtree and the right subtree should have
26+
- If left < root < right, the subtree is valid
27+
- If the left subtree and the right subtree are valid, call the function recursively for the left and right subtrees.
28+
- before calling the function, update the range of values for the left and right subtrees
29+
- If the left subtree and the right subtree are valid, return True
30+
31+
Time complexity: O(N)
32+
- The function is called recursively for each node
33+
34+
Space complexity: O(N)
35+
- The function stores the range of values for each node
36+
"""
37+
38+
39+
class Solution1:
40+
def isValidBST(self, root: Optional[TreeNode]) -> bool:
41+
maximum = float("inf")
42+
minimum = float("-inf")
43+
return self.isValidSubTree(root, maximum, minimum)
44+
45+
def isValidSubTree(self, root, maximum, minimum):
46+
47+
if root is None:
48+
return True
49+
50+
if not minimum < root.val < maximum:
51+
return False
52+
53+
return self.isValidSubTree(
54+
root.left, root.val, minimum
55+
) and self.isValidSubTree(
56+
root.right, maximum, root.val
57+
)

0 commit comments

Comments
ย (0)