Skip to content

Commit eaa5c92

Browse files
committed
LeetCode 219. Contains Duplicate II
1 parent 38ee217 commit eaa5c92

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ Solutions to LeetCode problems. The first column links to the problem in LeetCod
122122
| [215. Kth Largest Element in an Array][lc215] | 🟠 Medium | [![python](res/py.png)][lc215py] |
123123
| [217. Contains Duplicate][lc217] | 🟢 Easy | [![python](res/py.png)][lc217py] |
124124
| [218. The Skyline Problem][lc218] | 🔴 Hard | [![python](res/py.png)][lc218py] |
125+
| [219. Contains Duplicate II][lc219] | 🟢 Easy | [![python](res/py.png)][lc219py] |
125126
| [226. Invert Binary Tree][lc226] | 🟢 Easy | [![python](res/py.png)][lc226py] |
126127
| [227. Basic Calculator II][lc227] | 🟠 Medium | [![python](res/py.png)][lc227py] |
127128
| [230. Kth Smallest Element in a BST][lc230] | 🟠 Medium | [![python](res/py.png)][lc230py] |
@@ -498,6 +499,8 @@ Solutions to LeetCode problems. The first column links to the problem in LeetCod
498499
[lc217py]: leetcode/contains-duplicate.py
499500
[lc218]: https://leetcode.com/problems/the-skyline-problem/
500501
[lc218py]: leetcode/the-skyline-problem.py
502+
[lc219]: https://leetcode.com/problems/contains-duplicate-ii/
503+
[lc219py]: leetcode/contains-duplicate-ii.py
501504
[lc226]: https://leetcode.com/problems/invert-binary-tree/
502505
[lc226py]: leetcode/invert-binary-tree.py
503506
[lc227]: https://leetcode.com/problems/basic-calculator-ii/

leetcode/contains-duplicate-ii.py

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# 219. Contains Duplicate II
2+
# 🟢 Easy
3+
#
4+
# https://leetcode.com/problems/contains-duplicate-ii/
5+
#
6+
# Tags: Array - Hash Table - Sliding Window
7+
8+
import timeit
9+
from typing import List
10+
11+
12+
# We can keep values that we have seen in a hash map with their index
13+
# as a value, we iterate over the entire input checking if the index of
14+
# the last time we saw the same value is within range.
15+
#
16+
# Time complexity: O(n) - We process each element once.
17+
# Space complexity: O(n) - The hashmap can grow to the same size as the
18+
# input.
19+
#
20+
# Runtime: 1361 ms, faster than 49.15%
21+
# Memory Usage: 27.2 MB, less than 53.63%
22+
class HashMapAndDiff:
23+
def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
24+
# A dictionary of values pointing to the last index
25+
seen = {}
26+
for i, num in enumerate(nums):
27+
if num in seen and i - seen[num] <= k:
28+
return True
29+
# We can safely overwrite the last index of i because we
30+
# only care about the smallest difference.
31+
seen[num] = i
32+
return False
33+
34+
35+
# If len(nums) is much greater than k, we can optimize but only keeping
36+
# a sliding window of k values in the seen set.
37+
#
38+
# Time complexity: O(n) - We process each element once.
39+
# Space complexity: O(k) - The hash set can grow to size k.
40+
#
41+
# Runtime: 707 ms, faster than 83.95%
42+
# Memory Usage: 25.6 MB, less than 87.40%
43+
class SlidingWindow:
44+
def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
45+
# Base case, with k == 0, we can't have duplicates.
46+
if not k:
47+
return False
48+
seen = set()
49+
l = r = 0
50+
while r < len(nums):
51+
# If this value is in the set, we are done.
52+
if nums[r] in seen:
53+
return True
54+
# Add the value under the right pointer, then shift it.
55+
seen.add(nums[r])
56+
r += 1
57+
# If the set has reached full capacity move the left pointer
58+
# and pop its value.
59+
if len(seen) > k:
60+
seen.remove(nums[l])
61+
l += 1
62+
return False
63+
64+
65+
def test():
66+
executors = [
67+
HashMapAndDiff,
68+
SlidingWindow,
69+
]
70+
tests = [
71+
[[1], 3, False],
72+
[[1, 1], 1, True],
73+
[[1, 1], 0, False],
74+
[[1, 0, 1, 1], 1, True],
75+
[[1, 2, 3, 1], 3, True],
76+
[[1, 2, 3, 1, 2, 3], 2, False],
77+
]
78+
for executor in executors:
79+
start = timeit.default_timer()
80+
for _ in range(1):
81+
for col, t in enumerate(tests):
82+
sol = executor()
83+
result = sol.containsNearbyDuplicate(t[0], t[1])
84+
exp = t[2]
85+
assert result == exp, (
86+
f"\033[93m» {result} <> {exp}\033[91m for"
87+
+ f" test {col} using \033[1m{executor.__name__}"
88+
)
89+
stop = timeit.default_timer()
90+
used = str(round(stop - start, 5))
91+
cols = "{0:20}{1:10}{2:10}"
92+
res = cols.format(executor.__name__, used, "seconds")
93+
print(f"\033[92m» {res}\033[0m")
94+
95+
96+
test()

0 commit comments

Comments
 (0)