Loading problems...
TL;DR: The optimal solution uses a Hash Set to maintain a sliding window of the most recent elements, allowing for duplicate detection.
The LeetCode 219 problem, "Contains Duplicate II," asks us to determine if an integer array nums contains any duplicate elements located within a specific proximity. specifically, we need to return true if there exist two distinct indices and such that and the absolute difference between the indices is at most (). If no such pair exists, we return .
nums[i] == nums[j]falseThis is a popular interview question because it tests the ability to optimize a search operation within a localized range of an array.
The naive approach involves checking every possible pair of indices in the array to see if they satisfy both conditions: value equality and index proximity.
We iterate through each element at index and then iterate through subsequent elements at index where . For each pair, we check if nums[i] == nums[j].
Pseudo-code:
textfor i from 0 to length(nums) - 1: for j from i + 1 to min(i + k, length(nums) - 1): if nums[i] == nums[j]: return true return false
Time Complexity Analysis: The outer loop runs times. The inner loop runs up to times. In the worst case (where is close to ), this results in a time complexity of or roughly .
Why it fails:
The constraints allow nums.length up to and up to . An solution will perform approximately operations in the worst case, leading to a Time Limit Exceeded (TLE) error. We need a linear time solution.
The brute force approach is inefficient because it repeatedly scans the same elements to check for duplicates. For every index , we look ahead at the next elements. When we move to , we look at almost the same set of elements again.
The key insight is to maintain a "memory" of the elements currently within the valid distance . As we iterate through the array with a pointer right, we are effectively considering a window ending at right.
To satisfy the condition , we only care about elements in the range [right - k, right - 1]. By maintaining a Hash Set representing this sliding window, we can check if nums[right] exists in the set in time.
The pattern enforces a strict constraint: The window size must not exceed .
right, we add elements to our window (Hash Set).left and right is greater than ), we shrink the window from the left by removing nums[left] from the set.Visual Description: Imagine a window frame that can hold at most numbers sliding across the array from left to right. As the frame moves one step forward to include a new number, the oldest number (if the frame is full) drops out of the back. We simply check if the new number entering the frame matches any number currently inside it.

Let's trace the algorithm with nums = [1, 2, 3, 1] and k = 3.
window = {}, left = 0.val = 1
1 is not in window.1. window = {1}.val = 2
2 is not in window.2. window = {1, 2}.val = 3
3 is not in window.3. window = {1, 2, 3}.val = 1
1 IS in window.Now consider nums = [1, 2, 3, 1, 2, 3] and k = 2.
...
right reaches index 3 (val = 1):
[1, 2] (values {2, 3}).1) was removed because index .1 is not in {2, 3}. Add 1.The algorithm relies on the invariant that the Hash Set contains exactly the elements from the subarray nums[max(0, right-k) ... right-1].
right = j), the index will satisfy . Therefore, nums[i] will still be present in the Hash Set. The check window.contains(nums[right]) will correctly return true.nums[left] as soon as right - left > k. Thus, if window.contains(nums[right]) returns true, the matching element must be at an index such that right - i <= k. This satisfies the problem constraints.cppclass Solution { public: bool containsNearbyDuplicate(vector<int>& nums, int k) { // Hash set to store elements in the current window of size k unordered_set<int> window; int left = 0; for (int right = 0; right < nums.size(); ++right) { // If window size exceeds k, shrink from the left if (right - left > k) { window.erase(nums[left]); left++; } // Check if current element exists in the window if (window.count(nums[right])) { return true; } // Add current element to the window window.insert(nums[right]); } return false; } };
javaclass Solution { public boolean containsNearbyDuplicate(int[] nums, int k) { // Hash set to store elements in the current window of size k Set<Integer> window = new HashSet<>(); int left = 0; for (int right = 0; right < nums.length; right++) { // If window size exceeds k, shrink from the left if (right - left > k) { window.remove(nums[left]); left++; } // Check if current element exists in the window if (window.contains(nums[right])) { return true; } // Add current element to the window window.add(nums[right]); } return false; } }
pythonclass Solution: def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool: # Hash set to store elements in the current window of size k window = set() left = 0 for right in range(len(nums)): # If window size exceeds k, shrink from the left if right - left > k: window.remove(nums[left]) left += 1 # Check if current element exists in the window if nums[right] in window: return True # Add current element to the window window.add(nums[right]) return False
The Sliding Window - Variable Size pattern is versatile. Understanding how to maintain window invariants (like "size " or "unique characters") applies directly to:
Why does my solution get Time Limit Exceeded (TLE)?
contains) in a list is an operation. Inside the loop, this degrades the total complexity to .Why is my logic failing for small k?
nums[left] when the window slides.true for duplicates that are too far apart (e.g., indices 0 and 100 with ).Why do I get an index out of bounds error?
left pointer or the removal condition, specifically using if (right > k) vs if (right - left > k) without managing left correctly.nums[left] with the increment of left.