You are given an integer array nums and an integer k, return true if there are two distinct indicesi and j in the array such that nums[i] == nums[j] and abs(i - j) <= k, otherwise return false.
Please upgrade to NeetCode Pro to view company tags.
Prerequisites
Before attempting this problem, you should be comfortable with:
Hash Map / Hash Set - Used for O(1) lookups to track element indices or check for duplicates within a window
Sliding Window Technique - Maintaining a fixed-size window of elements as you iterate through the array
1. Brute Force
Intuition
The simplest approach is to check every pair of elements. For each element, we look at all elements within distance k and check if any of them are equal. This guarantees finding a duplicate if one exists within the required distance.
Algorithm
Iterate through each index L from 0 to n-1.
For each L, iterate through index R from L+1 to min(n-1, L+k).
classSolution:defcontainsNearbyDuplicate(self, nums: List[int], k:int)->bool:for L inrange(len(nums)):for R inrange(L +1,min(len(nums), L + k +1)):if nums[L]== nums[R]:returnTruereturnFalse
publicclassSolution{publicbooleancontainsNearbyDuplicate(int[] nums,int k){for(intL=0;L< nums.length;L++){for(intR=L+1;R<Math.min(nums.length,L+ k +1);R++){if(nums[L]== nums[R]){returntrue;}}}returnfalse;}}
classSolution{public:boolcontainsNearbyDuplicate(vector<int>& nums,int k){for(int L =0; L < nums.size(); L++){for(int R = L +1; R <min((int)nums.size(), L + k +1); R++){if(nums[L]== nums[R]){returntrue;}}}returnfalse;}};
classSolution{/**
* @param {number[]} nums
* @param {number} k
* @return {boolean}
*/containsNearbyDuplicate(nums, k){for(letL=0;L< nums.length;L++){for(letR=L+1;R< Math.min(nums.length,L+ k +1);R++){if(nums[L]=== nums[R]){returntrue;}}}returnfalse;}}
publicclassSolution{publicboolContainsNearbyDuplicate(int[] nums,int k){for(int L =0; L < nums.Length; L++){for(int R = L +1; R < Math.Min(nums.Length, L + k +1); R++){if(nums[L]== nums[R]){returntrue;}}}returnfalse;}}
funccontainsNearbyDuplicate(nums []int, k int)bool{for L :=0; L <len(nums); L++{for R := L +1; R <min(len(nums), L+k+1); R++{if nums[L]== nums[R]{returntrue}}}returnfalse}funcmin(a, b int)int{if a < b {return a
}return b
}
class Solution {funcontainsNearbyDuplicate(nums: IntArray, k: Int): Boolean {for(L in nums.indices){for(R in L +1 until minOf(nums.size, L + k +1)){if(nums[L]== nums[R]){returntrue}}}returnfalse}}
classSolution{funccontainsNearbyDuplicate(_ nums:[Int],_ k:Int)->Bool{forLin0..<nums.count {forRin(L+1)..<min(nums.count,L+ k +1){if nums[L]== nums[R]{returntrue}}}returnfalse}}
Time & Space Complexity
Time complexity: O(n∗min(n,k))
Space complexity: O(1)
Where n is the size of the array nums and k is the maximum distance between two equal numbers.
2. Hash Map
Intuition
Instead of checking all pairs, we can store the most recent index of each value in a hash map. When we encounter a value, we check if it appeared before and if the distance to its last occurrence is within k. This gives us O(1) lookup time for duplicates.
Algorithm
Create a hash map to store each value's most recent index.
Iterate through the array with index i.
If nums[i] exists in the map and i - map[nums[i]] <= k, return true.
Update map[nums[i]] = i (store the current index).
classSolution:defcontainsNearbyDuplicate(self, nums: List[int], k:int)->bool:
mp ={}for i inrange(len(nums)):if nums[i]in mp and i - mp[nums[i]]<= k:returnTrue
mp[nums[i]]= i
returnFalse
publicclassSolution{publicbooleancontainsNearbyDuplicate(int[] nums,int k){Map<Integer,Integer> map =newHashMap<>();for(int i =0; i < nums.length; i++){if(map.containsKey(nums[i])&& i - map.get(nums[i])<= k){returntrue;}
map.put(nums[i], i);}returnfalse;}}
classSolution{public:boolcontainsNearbyDuplicate(vector<int>& nums,int k){
unordered_map<int,int> mp;for(int i =0; i < nums.size(); i++){if(mp.find(nums[i])!= mp.end()&& i - mp[nums[i]]<= k){returntrue;}
mp[nums[i]]= i;}returnfalse;}};
classSolution{/**
* @param {number[]} nums
* @param {number} k
* @return {boolean}
*/containsNearbyDuplicate(nums, k){const map =newMap();for(let i =0; i < nums.length; i++){if(map.has(nums[i])&& i - map.get(nums[i])<= k){returntrue;}
map.set(nums[i], i);}returnfalse;}}
publicclassSolution{publicboolContainsNearbyDuplicate(int[] nums,int k){Dictionary<int,int> mp =newDictionary<int,int>();for(int i =0; i < nums.Length; i++){if(mp.ContainsKey(nums[i])&& i - mp[nums[i]]<= k){returntrue;}
mp[nums[i]]= i;}returnfalse;}}
funccontainsNearbyDuplicate(nums []int, k int)bool{
mp :=make(map[int]int)for i, num :=range nums {if j, ok := mp[num]; ok && i-j <= k {returntrue}
mp[num]= i
}returnfalse}
class Solution {funcontainsNearbyDuplicate(nums: IntArray, k: Int): Boolean {val mp = mutableMapOf<Int, Int>()for(i in nums.indices){if(mp.containsKey(nums[i])&& i - mp[nums[i]]!!<= k){returntrue}
mp[nums[i]]= i
}returnfalse}}
classSolution{funccontainsNearbyDuplicate(_ nums:[Int],_ k:Int)->Bool{var mp =[Int:Int]()for i in0..<nums.count {iflet j = mp[nums[i]], i - j <= k {returntrue}
mp[nums[i]]= i
}returnfalse}}
Time & Space Complexity
Time complexity: O(n)
Space complexity: O(n)
Where n is the size of the array nums and k is the maximum distance between two equal numbers.
3. Hash Set
Intuition
We only need to check for duplicates within a sliding window of size k. Using a hash set, we maintain exactly the elements in the current window. If a new element already exists in the set, we found a duplicate within distance k. We slide the window by removing the leftmost element when the window exceeds size k.
Algorithm
Create an empty hash set to represent the sliding window.
Use two pointers L and R, with R iterating through the array.
If the window size R - L exceeds k, remove nums[L] from the set and increment L.
classSolution:defcontainsNearbyDuplicate(self, nums: List[int], k:int)->bool:
window =set()
L =0for R inrange(len(nums)):if R - L > k:
window.remove(nums[L])
L +=1if nums[R]in window:returnTrue
window.add(nums[R])returnFalse
publicclassSolution{publicboolContainsNearbyDuplicate(int[] nums,int k){HashSet<int> window =newHashSet<int>();int L =0;for(int R =0; R < nums.Length; R++){if(R - L > k){
window.Remove(nums[L]);
L++;}if(window.Contains(nums[R])){returntrue;}
window.Add(nums[R]);}returnfalse;}}
funccontainsNearbyDuplicate(nums []int, k int)bool{
window :=make(map[int]bool)
L :=0for R :=0; R <len(nums); R++{if R-L > k {delete(window, nums[L])
L++}if window[nums[R]]{returntrue}
window[nums[R]]=true}returnfalse}
class Solution {funcontainsNearbyDuplicate(nums: IntArray, k: Int): Boolean {val window = HashSet<Int>()var L =0for(R in nums.indices){if(R - L > k){
window.remove(nums[L])
L++}if(nums[R]in window){returntrue}
window.add(nums[R])}returnfalse}}
Where n is the size of the array nums and k is the maximum distance between two equal numbers.
Common Pitfalls
Off-by-One Error in Distance Check
The condition requires the distance to be "at most k", meaning abs(i - j) <= k, not < k. Using strict inequality will miss valid pairs that are exactly k positions apart.
# Wrong: Using strict inequalityif nums[i]in mp and i - mp[nums[i]]< k:# Misses distance == k# Correct: Use <= for "at most k"if nums[i]in mp and i - mp[nums[i]]<= k:
Storing All Indices Instead of Most Recent
The hash map only needs to store the most recent index for each value. Storing all indices wastes memory and complicates the logic. Since we iterate left to right, we only care about the closest previous occurrence.