Given an integer array nums
and an integer k
, determine if there are two distinct indices i
and j
in the array such that nums[i] == nums[j]
and the absolute difference between i
and j
is at most k
(i.e., |i - j| ≤ k
).
true
if such a pair exists, otherwise return false
.nums
can be reused only at different indices (i.e., you cannot use the same index twice).1 ≤ nums.length ≤ 105
and -109 ≤ nums[i] ≤ 109
.
To solve this problem, first consider the brute-force approach: for every element, check all other elements within k
indices to see if any are equal. However, this quickly becomes inefficient for large arrays because it requires nested loops and many repeated comparisons.
To optimize, think about how you might keep track of the numbers you've seen so far and their positions. If you could instantly know whether a duplicate of the current number exists within the last k
indices, you could answer the question much faster. This leads to the idea of using a data structure for quick lookups, such as a hash map (dictionary).
The hash map will store each number as a key and its most recent index as the value. As you iterate through the array, you can check if the current number is already in the map and whether the difference in indices is at most k
. If so, return true
. Otherwise, update the map with the latest index for that number.
i
and value num
:
num
is already in the hash map.i
and the index stored in the map.k
, return true
immediately.num
.false
.
k
elements, but the hash map approach is more direct for this problem.
Consider the input nums = [1, 2, 3, 1]
and k = 3
:
{1: 0}
{1: 0, 2: 1}
{1: 0, 2: 1, 3: 2}
3 - 0 = 3 ≤ 3
, so return true
.
The process stops as soon as the duplicate within k
indices is found.
k
neighbors.n
entries in the worst case.
The key insight is to use a hash map to efficiently track the most recent index of each number. This allows you to check for duplicates within k
indices in constant time per element, reducing the overall time complexity from O(nk) to O(n). The approach is both simple and powerful, making it well-suited for large input sizes.
class Solution:
def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
num_indices = {}
for i, num in enumerate(nums):
if num in num_indices and i - num_indices[num] <= k:
return True
num_indices[num] = i
return False
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
unordered_map<int, int> num_indices;
for (int i = 0; i < nums.size(); ++i) {
if (num_indices.count(nums[i]) && i - num_indices[nums[i]] <= k) {
return true;
}
num_indices[nums[i]] = i;
}
return false;
}
};
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
Map<Integer, Integer> numIndices = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (numIndices.containsKey(nums[i]) && i - numIndices.get(nums[i]) <= k) {
return true;
}
numIndices.put(nums[i], i);
}
return false;
}
}
var containsNearbyDuplicate = function(nums, k) {
const numIndices = new Map();
for (let i = 0; i < nums.length; i++) {
if (numIndices.has(nums[i]) && i - numIndices.get(nums[i]) <= k) {
return true;
}
numIndices.set(nums[i], i);
}
return false;
};