Skip to content

Commit a7869aa

Browse files
committed
LeetCode 641. Design Circular Deque
1 parent b20a7e4 commit a7869aa

File tree

2 files changed

+164
-0
lines changed

2 files changed

+164
-0
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ Solutions to LeetCode problems. The first column links to the problem in LeetCod
175175
| [629. K Inverse Pairs Array][lc629] | 🔴 Hard | [![python](res/py.png)][lc629py] |
176176
| [630. Course Schedule III][lc630] | 🔴 Hard | [![python](res/py.png)][lc630py] |
177177
| [637. Average of Levels in Binary Tree][lc637] | 🟢 Easy | [![python](res/py.png)][lc637py] |
178+
| [641. Design Circular Deque][lc641] | 🟠 Medium | [![python](res/py.png)][lc641py] |
178179
| [659. Split Array into Consecutive Subsequences][lc659] | 🟠 Medium | [![python](res/py.png)][lc659py] |
179180
| [665. Non-decreasing Array][lc665] | 🟠 Medium | [![python](res/py.png)][lc665py] |
180181
| [692. Top K Frequent Words][lc692] | 🟠 Medium | [![python](res/py.png)][lc692py] |
@@ -561,6 +562,8 @@ Solutions to LeetCode problems. The first column links to the problem in LeetCod
561562
[lc630py]: leetcode/course-schedule-iii.py
562563
[lc637]: https://leetcode.com/problems/average-of-levels-in-binary-tree/
563564
[lc637py]: leetcode/average-of-levels-in-binary-tree.py
565+
[lc641]: https://leetcode.com/problems/design-circular-deque/
566+
[lc641py]: leetcode/design-circular-deque.py
564567
[lc659]: https://leetcode.com/problems/split-array-into-consecutive-subsequences/
565568
[lc659py]: leetcode/split-array-into-consecutive-subsequences.py
566569
[lc665]: https://leetcode.com/problems/non-decreasing-array/

leetcode/design-circular-deque.py

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

0 commit comments

Comments
 (0)