Skip to content

Commit d0911b8

Browse files
committed
new file: Additional Exercises/Easy 346. Moving Average from Data Stream.py
new file: Additional Exercises/Medium 426. Convert Binary Search Tree to Sorted Doubly Linked List.py new file: Additional Exercises/Medium 71. Simplify Path.py new file: Additional Exercises/Medium 841. Keys and Rooms.py modified: README.md
1 parent 96cf247 commit d0911b8

5 files changed

+324
-5
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from collections import deque
2+
3+
# Date of Last Practice: Mar 16, 2024
4+
#
5+
# Time Complexity: O(1). We only have a constant amount of computation.
6+
#
7+
# Space Complexity: O(N), where N is size and size is the maximum number of elements in the window.
8+
# This is because it maintains a deque (double-ended queue)
9+
# that contains at most size elements,
10+
# where size is the maximum number of elements in the window.
11+
12+
13+
class MovingAverage:
14+
# Step 1 - Initialize the class with maximum size, window, and sum tracker
15+
def __init__(self, size: int):
16+
self.max_size = size
17+
self.window = deque([])
18+
self.sum_of_window = 0
19+
20+
# Step 2 - Add a new value and calculate the moving average
21+
def next(self, val: int) -> float:
22+
# If the window is full, remove the oldest value
23+
if len(self.window) >= self.max_size:
24+
self.sum_of_window -= self.window.popleft()
25+
# Add the new value to the window and update the sum
26+
self.sum_of_window += val
27+
self.window.append(val)
28+
# Return the average
29+
return self.sum_of_window / len(self.window)
30+
31+
32+
# Step 3 - Test cases
33+
if __name__ == "__main__":
34+
movingAverage = MovingAverage(3)
35+
# Test the functionality with provided values
36+
assert movingAverage.next(1) == 1.0, "Test case 1 failed"
37+
assert movingAverage.next(10) == 5.5, "Test case 2 failed"
38+
assert movingAverage.next(3) == 4.666666666666667, "Test case 3 failed"
39+
assert movingAverage.next(5) == 6.0, "Test case 4 failed"
40+
print("All test cases passed!")
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
from typing import Optional
2+
3+
# Date of Last Practice: Mar 16, 2024
4+
#
5+
# Time Complexity: O(N), where N is the number of nodes in the tree.
6+
#
7+
# Space Complexity: O(N), where N is the number of nodes in the tree.
8+
# The space complexity consists of the space used by
9+
# the recursion call stack during the inorder traversal.
10+
# The height of a BST can be O(N) in the worst case
11+
# (completely unbalanced tree) and O(log N) in the best case
12+
# (completely balanced tree).
13+
14+
15+
class Node:
16+
def __init__(self, val=0, left=None, right=None):
17+
self.val = val
18+
self.left = left
19+
self.right = right
20+
21+
22+
class Solution:
23+
def treeToDoublyList(self, root: "Optional[Node]") -> "Optional[Node]":
24+
if not root:
25+
return None
26+
27+
# Initialize the previous and head node references
28+
self.prev = None
29+
self.head = None
30+
31+
# Step 1 - Perform inorder traversal to link nodes
32+
def _inorder_traversal(node):
33+
if not node:
34+
return
35+
36+
_inorder_traversal(node.left)
37+
38+
# For the first node, set it as the head
39+
if not self.prev:
40+
self.head = node
41+
else:
42+
# Link the current node with the previous one
43+
node.left = self.prev
44+
self.prev.right = node
45+
46+
self.prev = node
47+
48+
_inorder_traversal(node.right)
49+
50+
_inorder_traversal(root)
51+
52+
# Step 2 - Make the list circular
53+
self.head.left = self.prev
54+
self.prev.right = self.head
55+
56+
return self.head
57+
58+
59+
class AnotherSolution:
60+
# This solution has a space complexity of O(N).
61+
def treeToDoublyList(self, root: "Optional[Node]") -> "Optional[Node]":
62+
sorted_node = []
63+
64+
def _inorder_traversal(node):
65+
if node is None:
66+
return
67+
_inorder_traversal(node.left)
68+
sorted_node.append(node)
69+
_inorder_traversal(node.right)
70+
71+
_inorder_traversal(root)
72+
73+
head = None
74+
pre_node = None
75+
for index, node in enumerate(sorted_node):
76+
if index == 0:
77+
head = node
78+
head.left = sorted_node[-1]
79+
head.right = (
80+
sorted_node[index + 1] if index + 1 < len(sorted_node) else head
81+
)
82+
pre_node = head
83+
else:
84+
node.left = pre_node
85+
node.right = (
86+
sorted_node[index + 1] if index + 1 < len(sorted_node) else head
87+
)
88+
pre_node = node
89+
90+
return head
91+
92+
93+
# Test cases
94+
def test_solution():
95+
# Helper function to create a binary search tree from a list of values
96+
def create_bst_from_list(index, values):
97+
if index >= len(values) or values[index] is None:
98+
return None
99+
root = Node(values[index])
100+
root.left = create_bst_from_list(2 * index + 1, values)
101+
root.right = create_bst_from_list(2 * index + 2, values)
102+
return root
103+
104+
# Helper function to validate the doubly linked list
105+
def validate_dll(head, expected_values):
106+
values = []
107+
current = head
108+
for _ in range(len(expected_values)):
109+
values.append(current.val)
110+
current = current.right
111+
if current == head:
112+
break
113+
assert values == expected_values, f"Expected {expected_values}, got {values}"
114+
115+
sol = Solution()
116+
117+
# Test case 1
118+
values1 = [4, 2, 5, 1, 3]
119+
bst1 = create_bst_from_list(0, values1)
120+
head1 = sol.treeToDoublyList(bst1)
121+
validate_dll(head1, [1, 2, 3, 4, 5])
122+
123+
# Test case 2
124+
values2 = [2, 1, 3]
125+
bst2 = create_bst_from_list(0, values2)
126+
head2 = sol.treeToDoublyList(bst2)
127+
validate_dll(head2, [1, 2, 3])
128+
129+
print("All test cases passed!")
130+
131+
132+
test_solution()
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Date of Last Practice: Mar 16, 2024
2+
#
3+
# Time Complexity: O(N), where N is the length of the input path.
4+
# The time complexity of the given solution primarily depends on
5+
# the iteration over the path string once.
6+
#
7+
# Space Complexity: O(N), where N is the length of the input path.
8+
# In the worst-case scenario (where n is the number of characters in the path),
9+
# the folder_file_names list could potentially hold a fraction of the input
10+
# if the path contains many valid directory names.
11+
# The list size is proportional to the path's length in such scenarios.
12+
13+
14+
class Solution:
15+
def simplifyPath(self, path: str) -> str:
16+
# Step 1 - Split the path by '/'
17+
segments = path.split("/")
18+
19+
# Step 2 - Initialize a stack to hold directory names
20+
stack = []
21+
22+
for segment in segments:
23+
if segment == "..":
24+
# Step 3 - Pop last directory if '..' and stack is not empty
25+
if stack:
26+
stack.pop()
27+
# If segment == "" (empty string), this will be considered to be False in Python.
28+
elif segment and segment != ".":
29+
# Step 3 - Push directory name into stack
30+
stack.append(segment)
31+
32+
# Step 4 - Join the stack into a canonical path
33+
canonical_path = "/" + "/".join(stack)
34+
return canonical_path
35+
36+
37+
class BadSolution:
38+
# While this solution is effective, it is somewhat complex and not straightforward
39+
# due to the detailed handling of special cases (single and double dots, slashes)
40+
41+
def simplifyPath(self, path: str) -> str:
42+
folder_file_names = []
43+
dot_counter = 0
44+
45+
starting_index = None
46+
path += "/"
47+
for index, char in enumerate(path):
48+
if dot_counter == 1 and char == "/" and index - 2 == starting_index:
49+
dot_counter = 0
50+
starting_index = None
51+
elif dot_counter == 2 and char == "/" and index - 3 == starting_index:
52+
if folder_file_names:
53+
folder_file_names.pop()
54+
dot_counter = 0
55+
starting_index = None
56+
elif (dot_counter == 1 or dot_counter == 2) and char != ".":
57+
dot_counter = 0
58+
59+
if char == "/":
60+
if starting_index is None or index - 1 == starting_index:
61+
starting_index = index
62+
else:
63+
folder_file_names.append(path[starting_index + 1 : index])
64+
starting_index = index
65+
dot_counter = 0
66+
elif char == ".":
67+
dot_counter += 1
68+
69+
canonical_path = "/" + "/".join(folder_file_names)
70+
return canonical_path
71+
72+
73+
# Test cases
74+
solution = Solution()
75+
76+
# Test case 1
77+
assert solution.simplifyPath("/home/") == "/home"
78+
79+
# Test case 2
80+
assert solution.simplifyPath("/../") == "/"
81+
82+
# Test case 3
83+
assert solution.simplifyPath("/home//foo/") == "/home/foo"
84+
85+
# Test case 4 - More complex path
86+
assert solution.simplifyPath("/a/./b/../../c/") == "/c"
87+
88+
# Test case 5 - Path with multiple sequential slashes and dots
89+
assert solution.simplifyPath("/a//b////c/d//././/..") == "/a/b/c"
90+
91+
print("All test cases passed successfully.")
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from collections import deque
2+
from typing import List
3+
4+
# Date of Last Practice: Mar 16, 2024
5+
#
6+
# Time Complexity: O(N+K), where N is the number of rooms, and K is the total number of keys.
7+
# The sum of all keys (rooms[i].length) across all rooms is bounded by 3000,
8+
# and each key leads to a room that will be visited at most once.
9+
#
10+
# Space Complexity: O(N+K), where N is the number of rooms, and K is the total number of keys.
11+
# The visited_room set will at most contain n elements if all rooms are visited.
12+
# The key_queue can at most contain all the keys found in the rooms at any point.
13+
14+
15+
class Solution:
16+
def canVisitAllRooms(self, rooms: List[List[int]]) -> bool:
17+
# Initialize a queue for BFS and a set to keep track of visited rooms
18+
key_queue = deque(rooms[0])
19+
visited_room = {0}
20+
21+
while key_queue:
22+
# Pop the first key from the queue
23+
room_to_open = key_queue.popleft()
24+
if room_to_open in visited_room:
25+
continue
26+
# Add all new keys found in the room to the queue
27+
for key in rooms[room_to_open]:
28+
if key not in visited_room:
29+
key_queue.append(key)
30+
# Mark the current room as visited
31+
visited_room.add(room_to_open)
32+
33+
# If all rooms have been visited, return True
34+
return len(visited_room) == len(rooms)
35+
36+
37+
# Test cases
38+
sol = Solution()
39+
40+
# Test case 1: Possible to visit all rooms
41+
rooms1 = [[1], [2], [3], []]
42+
assert sol.canVisitAllRooms(rooms1) == True
43+
44+
# Test case 2: Impossible to visit room 2
45+
rooms2 = [[1, 3], [3, 0, 1], [2], [0]]
46+
assert sol.canVisitAllRooms(rooms2) == False
47+
48+
# Example of a more complex test case
49+
rooms3 = [[1, 2, 3], [4], [5], [6], [7], [8], [9], [10], [11], [], [], []]
50+
assert sol.canVisitAllRooms(rooms3) == True
51+
52+
print("All tests passed!")

README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,20 +114,24 @@ Current Progress: 72/75.
114114

115115
- [x] [Easy 408. Valid Word Abbreviation](https://leetcode.com/problems/valid-word-abbreviation/description/)
116116
- [x] [Easy 680. Valid Palindrome II](https://leetcode.com/problems/valid-palindrome-ii/) | Algo: Two-Pointer Technique
117+
- [x] [Easy 938. Range Sum of BST](https://leetcode.com/problems/range-sum-of-bst/)
117118
- [x] [Medium 2. Add Two Numbers](https://leetcode.com/problems/add-two-numbers/description/) | Algo: Carry Management
118119
- [x] [Medium 138. Copy List with Random Pointer](https://leetcode.com/problems/copy-list-with-random-pointer/description/) | DS: Linked List
120+
- [x] [Medium 215. Kth Largest Element in an Array](https://leetcode.com/problems/buildings-with-an-ocean-view/description/) | Algo: Quickselect (Fastest in Average Cases), DS: Heap (Good in All Cases)
119121
- [x] ⭐️ [Medium 227. Basic Calculator](https://leetcode.com/problems/basic-calculator-ii/description/) | DS: Stack
120122
- [x] [Medium 314. Binary Tree Vertical Order Traversal](https://leetcode.com/problems/binary-tree-vertical-order-traversal/) | Algo: Breadth-First Search (BFS), DS: Queue
121123
- [x] [Medium 339. Nested List Weight Sum](https://leetcode.com/problems/nested-list-weight-sum/description/)
124+
- [x] [Medium 426. Convert Binary Search Tree to Sorted Doubly Linked List](https://leetcode.com/problems/convert-binary-search-tree-to-sorted-doubly-linked-list/description/)
122125
- [x] ⭐️ [Medium 528. Random Pick with Weight.py](https://leetcode.com/problems/random-pick-with-weight/description/) | Algo: Binary Search; DS: Prefix Sum Array
123126
- [x] [Medium 763. Partition Labels](https://leetcode.com/problems/partition-labels/) | Algo: Two-Pointer Technique, Dynamic Sliding Window, Greedy Method
127+
- [x] [Medium 791. Custom Sort String](https://leetcode.com/problems/custom-sort-string/description/)
128+
- [x] [Medium 841. Keys and Rooms](https://leetcode.com/problems/keys-and-rooms/description/)
124129
- [x] [Medium 1249. Minimum Remove to Make Valid Parentheses](https://leetcode.com/problems/minimum-remove-to-make-valid-parentheses/description/) | DS: Stack
125130
- [x] [Medium 1570. Dot Product of Two Sparse Vectors](https://leetcode.com/problems/dot-product-of-two-sparse-vectors/)
126131
- [x] [Medium 1650. Lowest Common Ancestor of a Binary Tree III](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree-iii/) | Algo: Depth-First Search
127132
- [x] [Medium 1762. Buildings with an Ocean View](https://leetcode.com/problems/buildings-with-an-ocean-view/description/) | DS: Monotonic Stack
128133

129-
Sun:
130-
- [x] [Medium 215. Kth Largest Element in an Array](https://leetcode.com/problems/buildings-with-an-ocean-view/description/) | Algo: Quickselect (Fastest in Average Cases), DS: Heap (Good in All Cases)
131-
- [x] [Easy 938. Range Sum of BST](https://leetcode.com/problems/range-sum-of-bst/)
132-
- [x] [Medium 791. Custom Sort String](https://leetcode.com/problems/custom-sort-string/description/)
133-
- [x] [Medium 426. Convert Binary Search Tree to Sorted Doubly Linked List](https://leetcode.com/problems/convert-binary-search-tree-to-sorted-doubly-linked-list/description/)
134+
## Today
135+
136+
- [x] [Easy 346. Moving Average from Data Stream](https://leetcode.com/problems/moving-average-from-data-stream/)
137+
- [x] ⭐️ [Medium 71. Simplify Path](https://leetcode.com/problems/simplify-path/description/)

0 commit comments

Comments
 (0)