Contains Duplicate II (LC 219)
On this page
Pattern: Sliding Window + HashSet
Difficulty: Easy
Key Concept: Maintain a window of k elements using a HashSet to detect duplicates
Problem Statement
Given an integer array nums and an integer k, return true if there are two distinct indices i and j such that nums[i] == nums[j] and abs(i - j) <= k.
- Input:
int[] nums,int k - Output:
boolean
1. Algorithm & Pseudocode
FUNCTION containsNearbyDuplicate(nums, k):
SET window = empty HashSet
FOR i = 0 TO nums.length - 1:
IF window contains nums[i]:
RETURN true
window.add(nums[i])
IF window.size() > k:
window.remove(nums[i - k])
RETURN false
2. Step-by-Step Analysis (Beginner-Friendly)
- Step 1: We maintain a “window” of at most
kelements using a HashSet. - Step 2: For each new element, check if it already exists in the window (meaning a duplicate within distance k).
- Step 3: Add the element to the window.
- Step 4: If the window exceeds size
k, remove the oldest element (the one that’s now too far away). - Why HashSet? It gives O(1) lookup for checking duplicates instead of scanning the window.
3. The Dry Run
Input: nums = [1, 2, 3, 1], k = 3
| Step | i | nums[i] | Window (before) | Contains? | Window (after) | Action |
|---|---|---|---|---|---|---|
| 1 | 0 | 1 | {} | No | {1} | Add 1 |
| 2 | 1 | 2 | {1} | No | {1, 2} | Add 2 |
| 3 | 2 | 3 | {1, 2} | No | {1, 2, 3} | Add 3 |
| 4 | 3 | 1 | {1, 2, 3} | Yes! | - | Return true |
Result: true (nums[0] == nums[3], distance = 3 <= k)
4. Java Solution
Brute Force
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j <= Math.min(i + k, nums.length - 1); j++) {
if (nums[i] == nums[j]) return true;
}
}
return false;
}
}
Optimal
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
Set<Integer> window = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
if (!window.add(nums[i])) return true;
if (window.size() > k) {
window.remove(nums[i - k]);
}
}
return false;
}
}
5. The “Java vs. Others” Edge
HashSet.add()returnsboolean: Returnsfalseif element already exists. This is a powerful one-liner trick!if (!set.add(x))checks AND adds in one operation.- In C++:
unordered_set::insert()returns apair<iterator, bool>where.secondis the success flag. More verbose. - In Python: Sets don’t have this return value. You’d use
if x in windowfirst, thenwindow.add(x). window.remove(nums[i - k]): HashSet.remove() is O(1) average. No need for an ordered data structure since we only care about presence, not position.- Autoboxing:
nums[i]isintbutHashSet<Integer>storesIntegerobjects. Java auto-boxes. For very large arrays, this adds overhead vs primitive-based sets (like Eclipse CollectionsIntHashSet).
6. Complexity Summary
| Approach | Time | Space | Notes |
|---|---|---|---|
| Brute Force | O(n * k) | O(1) | Check next k elements for each |
| Sliding Window + HashSet | O(n) | O(k) | Window of at most k elements |