-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathdesign-circular-deque.py
161 lines (141 loc) · 4.44 KB
/
design-circular-deque.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# 641. Design Circular Deque
# 🟠 Medium
#
# https://leetcode.com/problems/design-circular-deque/
#
# Tags: Array - Linked List - Design - Queue
from __future__ import annotations
import timeit
from data import serializeLinkedList
# A doubly linked list node.
class DListNode:
def __init__(
self,
prev: DListNode = None,
next: DListNode = None,
val: int = 0,
):
self.prev = prev
self.next = next
self.val = val
def __repr__(self):
return f"DListNode({self.val})"
# Create a data structure that complies with the given requirements.
# One way to do it is to use a doubly linked list.
#
# Runtime: 187 ms, faster than 5.29%
# Memory Usage: 15 MB, less than 20.44%
class MyCircularDeque:
def __init__(self, k: int):
self.max_size = k
self.current_size = 0
self.back = None
self.front = None
# Insert to the front in O(1)
def insertFront(self, value: int) -> bool:
if self.isFull():
return False
node = DListNode(val=value)
if self.isEmpty():
self.back = node
else:
self.front.prev = node
node.next = self.front
self.front = node
self.current_size += 1
return True
# Insert to the back in O(1)
def insertLast(self, value: int) -> bool:
if self.isFull():
return False
node = DListNode(val=value)
if self.isEmpty():
self.front = node
else:
self.back.next = node
node.prev = self.back
self.back = node
self.current_size += 1
return True
# Delete from the front in O(1)
def deleteFront(self) -> bool:
if self.isEmpty():
return False
if self.current_size == 1:
self.back = self.front = None
else:
self.front = self.front.next
self.front.prev = None
self.current_size -= 1
return True
# Delete from the back in O(1)
def deleteLast(self) -> bool:
if self.isEmpty():
return False
if self.current_size == 1:
self.back = self.front = None
else:
self.back = self.back.prev
self.back.next = None
self.current_size -= 1
return True
# Get the element at the front of the queue in O(1)
def getFront(self) -> int:
if self.isEmpty():
return -1
return self.front.val
# Get the element at the back of the queue in O(1)
def getRear(self) -> int:
if self.isEmpty():
return -1
return self.back.val
# Check if the queue is empty in O(1)
def isEmpty(self) -> bool:
return self.current_size == 0
# Check if the queue is full in O(1)
def isFull(self) -> bool:
return self.current_size == self.max_size
def test():
executors = [MyCircularDeque]
tests = [
[
[
"MyCircularDeque",
"insertLast",
"insertLast",
"insertFront",
"insertFront",
"getRear",
"isFull",
"deleteLast",
"insertFront",
"getFront",
],
[[3], [1], [2], [3], [4], [], [], [], [4], []],
[None, True, True, True, False, 2, True, True, True, 4],
],
]
for executor in executors:
start = timeit.default_timer()
for _ in range(1):
for col, t in enumerate(tests):
# The capacity comes wrapped in an array, unwrap it.
sol = executor(t[1][0][0])
for i in range(1, len(t[0])):
call = t[0][i]
# Only the enqueue call takes arguments
if call == "insertLast" or call == "insertFront":
result = getattr(sol, call)(t[1][i][0])
else:
result = getattr(sol, call)()
exp = t[2][i]
assert result == exp, (
f"\033[93m» {result} <> {exp}\033[91m for"
+ f" test {col} using \033[1m{executor.__name__}"
)
stop = timeit.default_timer()
used = str(round(stop - start, 5))
cols = "{0:20}{1:10}{2:10}"
res = cols.format(executor.__name__, used, "seconds")
print(f"\033[92m» {res}\033[0m")
test()