Skip to content

Commit a7ec852

Browse files
committed
8/25/23
Shooting for 10: 1) evaluate_rpn.py 2) is_valid_parenthsization.py 3) directory_path_normalization.py 4) sunset_view.py 5) queue_from_stacks.py 6) queue_with_max.py 7) circular_queue.py
1 parent 29c894d commit a7ec852

8 files changed

+255
-31
lines changed

elements-of-programming-interviews/problem_mapping.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -896,7 +896,7 @@ problem_mapping = {
896896
"total": 108
897897
},
898898
"Python: evaluate_rpn.py": {
899-
"passed": 0,
899+
"passed": 108,
900900
"total": 108
901901
}
902902
},
@@ -910,7 +910,7 @@ problem_mapping = {
910910
"total": 78
911911
},
912912
"Python: is_valid_parenthesization.py": {
913-
"passed": 0,
913+
"passed": 78,
914914
"total": 78
915915
}
916916
},
@@ -924,7 +924,7 @@ problem_mapping = {
924924
"total": 255
925925
},
926926
"Python: directory_path_normalization.py": {
927-
"passed": 0,
927+
"passed": 255,
928928
"total": 255
929929
}
930930
},
@@ -938,7 +938,7 @@ problem_mapping = {
938938
"total": 101
939939
},
940940
"Python: sunset_view.py": {
941-
"passed": 0,
941+
"passed": 101,
942942
"total": 101
943943
}
944944
},
@@ -966,7 +966,7 @@ problem_mapping = {
966966
"total": 65
967967
},
968968
"Python: circular_queue.py": {
969-
"passed": 0,
969+
"passed": 65,
970970
"total": 65
971971
}
972972
},
@@ -980,7 +980,7 @@ problem_mapping = {
980980
"total": 65
981981
},
982982
"Python: queue_from_stacks.py": {
983-
"passed": 0,
983+
"passed": 65,
984984
"total": 65
985985
}
986986
},
@@ -994,7 +994,7 @@ problem_mapping = {
994994
"total": 201
995995
},
996996
"Python: queue_with_max.py": {
997-
"passed": 0,
997+
"passed": 201,
998998
"total": 201
999999
}
10001000
}

elements-of-programming-interviews/python/circular_queue.py

+43-6
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,57 @@
44

55
class Queue:
66
def __init__(self, capacity: int) -> None:
7-
# TODO - you fill in here.
7+
if capacity < 1:
8+
raise RuntimeError(f"Queue must have at positive capacity (cannot use {capacity}).")
9+
self.capacity = capacity
10+
self.data = [""] * capacity
11+
self._size = 0
12+
self.tail = None
13+
self.head = None
814
return
915

16+
def _resize(self, new_capacity):
17+
new_data = [""] * new_capacity
18+
head = self.head
19+
for i in range(self._size):
20+
new_data[i] = self.data[head]
21+
head = (head + 1) % self.capacity
22+
self.data = new_data
23+
self.capacity = new_capacity
24+
self.head = 0
25+
self.tail = self._size - 1
26+
1027
def enqueue(self, x: int) -> None:
11-
# TODO - you fill in here.
28+
if self._size == self.capacity:
29+
self._resize(self.capacity * 2)
30+
31+
if self.tail == self.head == None:
32+
self.head = self.tail = 0
33+
else:
34+
self.tail = (self.tail + 1) % self.capacity
35+
36+
self.data[self.tail] = x
37+
self._size += 1
1238
return
1339

1440
def dequeue(self) -> int:
15-
# TODO - you fill in here.
16-
return 0
41+
if self._size == 0:
42+
raise RuntimeError("Cannot dequeue from empty queue.")
43+
val = self.data[self.head]
44+
self.data[self.head] = ""
45+
46+
self._size -= 1
47+
if self._size == 0:
48+
self.tail = self.head = None
49+
else:
50+
self.head = (self.head + 1) % self.capacity
51+
return val
1752

1853
def size(self) -> int:
19-
# TODO - you fill in here.
20-
return 0
54+
return self._size
55+
56+
def __repr__(self):
57+
return f"Queue(capacity: {self.capacity}, size: {self._size}, tail: {self.tail}, head: {self.head}, {self.data})"
2158

2259

2360
def queue_tester(ops):

elements-of-programming-interviews/python/directory_path_normalization.py

+91-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,101 @@
11
from test_framework import generic_test
22

33

4+
"""
5+
Allowed chars:
6+
- . (current path)
7+
- .. (parent dir)
8+
- / (subdir)
9+
- alphanum (dir name)
10+
- empty (same as .)
11+
12+
cases:
13+
- empty
14+
- /////// -> /
15+
- / -> /
16+
- /../.. -> /
17+
- ../.. -> ../..
18+
- derp -> derp
19+
- /derp -> /derp
20+
- /derp/.. -> /
21+
- derp/.. -> empty?
22+
- derp/../.. -> ..
23+
24+
- Paths can be absolute (begin at '/') or relative (begin at current dir)
25+
- for abspaths, / is highest parent; any '..' from '/' yields '/'
26+
- for relpaths, each '..' either pops the last known dir, or appends '..'
27+
"""
28+
29+
30+
def shortest_equivalent_path_first(path: str) -> str:
31+
"""
32+
- is absolute? (first char)
33+
- split path on '/'
34+
- keep stack
35+
- for each item in path list:
36+
- if char is ., skip it
37+
- if item is alphanum, push it
38+
- if item is ..:
39+
- if dir is absolute, pop if stack is nonempty, else skip
40+
- if dir is rel, pop if stack is nonempty and stack top not .., else push
41+
- return joined stack; prepend '/' is absolute path
42+
"""
43+
if not path:
44+
return path
45+
absolute = path[0] == '/'
46+
47+
stack = []
48+
dirs = [item for item in path.split('/') if item]
49+
for item in dirs:
50+
if item == "..":
51+
if absolute and stack:
52+
stack.pop()
53+
elif not absolute and (not stack or stack[-1] == ".."):
54+
stack.append(item)
55+
elif not absolute and stack and stack[-1] != "..":
56+
stack.pop()
57+
elif item == ".":
58+
continue
59+
else:
60+
stack.append(item)
61+
62+
return ("/" if absolute else "") + "/".join(stack)
63+
64+
465
def shortest_equivalent_path(path: str) -> str:
5-
# TODO - you fill in here.
6-
return ''
66+
if not path:
67+
return path
68+
69+
stack = []
70+
for item in (item for item in path.split('/') if (item and item != ".")):
71+
if item == "..":
72+
if stack and (path[0] == '/' or stack[-1] != ".."):
73+
stack.pop()
74+
else:
75+
stack.append(item)
76+
else:
77+
stack.append(item)
78+
79+
return ("/" if path.startswith('/') else "") + "/".join(stack)
780

881

982
if __name__ == '__main__':
83+
cases = [
84+
("", ""),
85+
("///////", "/"),
86+
("/", "/"),
87+
("/../..", "/"),
88+
("../..", "../.."),
89+
("derp", "derp"),
90+
("/derp", "/derp"),
91+
("/derp/..", "/"),
92+
("derp/..", ""),
93+
("derp/../..", "..")
94+
]
95+
for path, expected in cases:
96+
actual = shortest_equivalent_path(path)
97+
assert actual == expected, f"{path}: {actual} != {expected}"
98+
1099
exit(
11100
generic_test.generic_test_main('directory_path_normalization.py',
12101
'directory_path_normalization.tsv',
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,50 @@
11
from test_framework import generic_test
22

33

4+
OPERATIONS = ["*", "+", "/", "-"]
5+
6+
7+
def apply(operation, op1, op2):
8+
if operation == "*":
9+
return op1 * op2
10+
elif operation == "+":
11+
return op1+op2
12+
elif operation == "/":
13+
return op1 // op2
14+
else:
15+
return op1 - op2
16+
17+
418
def evaluate(expression: str) -> int:
5-
# TODO - you fill in here.
6-
return 0
19+
# NOTE: assuming valid expression
20+
if not expression:
21+
return 0
22+
stack = []
23+
expr = expression.split(",")
24+
for val in expr:
25+
if val not in OPERATIONS:
26+
stack.append(int(val))
27+
else:
28+
op2 = stack.pop()
29+
op1 = stack.pop()
30+
stack.append(apply(val, op1, op2))
31+
return stack.pop()
732

833

934
if __name__ == '__main__':
35+
"""
36+
cases = [
37+
("0", 0),
38+
("", 0),
39+
("4", 4),
40+
("-4", -4),
41+
("4,4,+", 8),
42+
("10,10,X,4,4,+,+,2,/", 54)
43+
44+
]
45+
for expression, expected in cases:
46+
assert evaluate(expression) == expected, f"{evaluate(expression)} != {expected}"
47+
"""
1048
exit(
1149
generic_test.generic_test_main('evaluate_rpn.py', 'evaluate_rpn.tsv',
1250
evaluate))

elements-of-programming-interviews/python/is_valid_parenthesization.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,22 @@
22

33

44
def is_well_formed(s: str) -> bool:
5-
# TODO - you fill in here.
6-
return True
5+
BRACES = {
6+
'{': '}',
7+
'(': ')',
8+
'[': ']'
9+
}
10+
stack = []
11+
for c in s:
12+
if c in BRACES:
13+
stack.append(c)
14+
elif not stack or not (c == BRACES[stack.pop()]):
15+
return False
16+
return len(stack) == 0
717

818

919
if __name__ == '__main__':
20+
# is_well_formed("()")
1021
exit(
1122
generic_test.generic_test_main('is_valid_parenthesization.py',
1223
'is_valid_parenthesization.tsv',

elements-of-programming-interviews/python/queue_from_stacks.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@
33

44

55
class Queue:
6+
def __init__(self):
7+
self.in_stack = []
8+
self.out_stack = []
9+
610
def enqueue(self, x: int) -> None:
7-
# TODO - you fill in here.
8-
return
11+
self.in_stack.append(x)
912

1013
def dequeue(self) -> int:
11-
# TODO - you fill in here.
12-
return 0
14+
if not self.out_stack:
15+
while self.in_stack:
16+
self.out_stack.append(self.in_stack.pop())
17+
return self.out_stack.pop()
1318

1419

1520
def queue_tester(ops):

elements-of-programming-interviews/python/queue_with_max.py

+38-6
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,51 @@
11
from test_framework import generic_test
22
from test_framework.test_failure import TestFailure
33

4+
"""
5+
- max stack uses separate stack
6+
- queue adds to end, releases from front.
7+
- any time we add to the end, the max can change;
8+
any time we release from front, too
9+
- likely not viable in O(c) time and space
10+
11+
- use a deque
12+
- each time we find a new max, dump the old deque, start with
13+
just current element
14+
- if we enqueue something less than current max, enqueue to deque
15+
- if the dequeued item matches current max, pop from deque
16+
"""
17+
18+
import collections
19+
420

521
class QueueWithMax:
22+
def __init__(self):
23+
self.data = collections.deque()
24+
self.max_vals = collections.deque()
25+
626
def enqueue(self, x: int) -> None:
7-
# TODO - you fill in here.
8-
return
27+
self.data.appendleft(x)
28+
if not self.max_vals:
29+
self.max_vals.append(x)
30+
return
31+
32+
if x > self.max_vals[-1]:
33+
self.max_vals = collections.deque([x])
34+
else:
35+
while self.max_vals[0] < x:
36+
self.max_vals.popleft()
37+
self.max_vals.appendleft(x)
938

1039
def dequeue(self) -> int:
11-
# TODO - you fill in here.
12-
return 0
40+
if self.data[-1] == self.max_vals[-1]:
41+
self.max_vals.pop()
42+
return self.data.pop()
1343

1444
def max(self) -> int:
15-
# TODO - you fill in here.
16-
return 0
45+
return self.max_vals[-1]
46+
47+
def __repr__(self):
48+
return f"QueueWithMax(data: {self.data}, maxes: {self.max_vals})"
1749

1850

1951
def queue_tester(ops):

0 commit comments

Comments
 (0)