
Problem Statement
In this challenge, you are provided with an integer array nums
and two integer values, indexDiff
and valueDiff
. Your task is to determine if there exists a pair of indices (i, j)
in the array where the following conditions are all satisfied:
- The indices
i
andj
are distinct (i.e.,i
is not equal toj
). - The absolute difference between
i
andj
does not exceedindexDiff
(abs(i - j) <= indexDiff
). - The absolute difference between the values at these indices does not exceed
valueDiff
(abs(nums[i] - nums[j]) <= valueDiff
).
The function should return true
if such a pair exists, otherwise false
.
Examples
Example 1
Input:
nums = [1,2,3,1], indexDiff = 3, valueDiff = 0
Output:
true
Explanation:
We can choose (i, j) = (0, 3). We satisfy the three conditions: i != j --> 0 != 3 abs(i - j) <= indexDiff --> abs(0 - 3) <= 3 abs(nums[i] - nums[j]) <= valueDiff --> abs(1 - 1) <= 0
Example 2
Input:
nums = [1,5,9,1,5,9], indexDiff = 2, valueDiff = 3
Output:
false
Explanation:
After trying all the possible pairs (i, j), we cannot satisfy the three conditions, so we return false.
Constraints
2 <= nums.length <= 105
-109 <= nums[i] <= 109
1 <= indexDiff <= nums.length
0 <= valueDiff <= 109
Approach and Intuition
The problem requires checking pairs in an array to fulfill both index and value difference constraints. Here's how to think about it:
Sliding Window Approach: Given the limitation by
indexDiff
on how far apart indices can be, this problem naturally leans towards a sliding window or two-pointer approach.- Iterate over the array and for each element, consider it as
nums[i]
. - Create a window (or subarray) that starts from
i+1
tomin(i + indexDiff, len(nums) - 1)
. - Check each element within this window:
- If any satisfies
abs(nums[i] - nums[j]) <= valueDiff
, returntrue
.
- If any satisfies
- Iterate over the array and for each element, consider it as
Use of Appropriate Data Structure: To efficiently check the condition
abs(nums[i] - nums[j]) <= valueDiff
, a balanced tree or a sorted data structure might help, but given typical constraint sizes, a simpler approach might work adequately, using direct computation.Boundary Checks:
- If
valueDiff
is0
, we are looking for exact duplicates within the allowed index range. - Always ensure that for the sliding window end point does not exceed array boundaries.
- If
With respect to the provided examples:
Example 1: "nums = [1,2,3,1], indexDiff = 3, valueDiff = 0". Directly iterate through
nums
and for eachi
, check other indices within the valid range. Here,nums[0]
andnums[3]
both are1
and within index distance3
, hence,true
.Example 2: Despite similar checks as in Example 1, no pairs
(i, j)
satisfy all given conditions due to larger differences in values compared to the allowedvalueDiff
, thus,false
.
Solutions
- C++
- Java
- Python
class Solution {
public:
long calculateBucketID(long element, long width) {
return element < 0 ? (element + 1) / width - 1 : element / width;
}
bool hasNearbyDuplicate(vector<int>& elements, int range, int tolerance) {
if (tolerance < 0) return false;
unordered_map<long, long> mapBuckets;
long width = (long)tolerance + 1;
for (int i = 0; i < elements.size(); ++i) {
long bucketID = calculateBucketID(elements[i], width);
if (mapBuckets.count(bucketID)) return true;
if (mapBuckets.count(bucketID - 1) &&
abs(elements[i] - mapBuckets[bucketID - 1]) < width)
return true;
if (mapBuckets.count(bucketID + 1) &&
abs(elements[i] - mapBuckets[bucketID + 1]) < width)
return true;
mapBuckets[bucketID] = (long)elements[i];
if (i >= range) {
mapBuckets.erase(calculateBucketID(elements[i - range], width));
}
}
return false;
}
};
The provided C++ solution addresses the problem of determining whether an array contains duplicates within a certain index range and value difference. Edit the hasNearbyDuplicate
function to explore an array of integers, using a system of logical bucketing whereby each element is assigned to a computed bucket ID based on its value and the allowed tolerance.
- Calculate Bucket ID: Private member function
calculateBucketID
computes and returns the bucket ID for a given element based on its value and the specified width (tolerance + 1
). It accounts for negative elements correctly by adjusting the bucket computation, ensuring accurate mapping. - Examine Duplicates with Conditions:
- Initialize a hash map
mapBuckets
to store elements mapped to their respective bucket IDs. - Define
width
as the tolerance increased by one, used for bucketing. - Iterate through the vector of elements.
- For each element, determine the current element's bucket ID.
- Check if this bucket ID, or the neighboring bucket IDs (one above or below), already exist in
mapBuckets
and meet the criteria of having an absolute difference less thanwidth
. If found, return true, indicating a duplicate under the specified conditions. - Update the current bucket ID in
mapBuckets
with the element. - If the current index surpasses the specified range (
range
), remove the oldest element's bucket frommapBuckets
to maintain the constraint of considering only the nearby elements.
- Initialize a hash map
- Conclusion: If no such duplicate is found by the end of the array, return false. This solution effectively uses a sliding window approach combined with bucketing to efficiently find duplicates within the specified range and tolerance in terms of indices and values.
class Solution {
// Determine the bucket ID
private long bucketId(long x, long width) {
return Math.floorDiv(x, width);
}
public boolean checkDuplicatesWithinK(int[] nums, int k, int t) {
if (t < 0) return false;
Map<Long, Long> map = new HashMap<>();
long bucketWidth = (long) t + 1;
for (int i = 0; i < nums.length; ++i) {
long currentBucketId = bucketId(nums[i], bucketWidth);
if (map.containsKey(currentBucketId)) return true;
if (map.containsKey(currentBucketId - 1) && Math.abs(nums[i] - map.get(currentBucketId - 1)) < bucketWidth)
return true;
if (map.containsKey(currentBucketId + 1) && Math.abs(nums[i] - map.get(currentBucketId + 1)) < bucketWidth)
return true;
map.put(currentBucketId, (long) nums[i]);
if (i >= k) map.remove(bucketId(nums[i - k], bucketWidth));
}
return false;
}
}
In the Java solution to the "Contains Duplicate III" problem, the task is to determine if there are any duplicates in the array such that:
- The absolute difference between two elements is at most
t
. - The absolute difference between their indices is at most
k
.
Here's how the solution works:
- Define a method
bucketId(long x, long width)
to calculate the bucket ID for an element considering the bucket width, which is set tot + 1
. The bucket ID is computed usingMath.floorDiv(x, width)
. - In the method
checkDuplicatesWithinK
, it initially checks ift < 0
, immediately returning false if true, as a negativet
doesn't make sense in the context of absolute differences. - The program then initializes a
HashMap
to track the elements and their corresponding bucket IDs. - Iterate through the array
nums
. For each element:- Calculate its bucket ID.
- Check if this bucket or its neighboring buckets (current ID +1 and current ID -1) already contain a value close enough (within the bucket width) to the current element.
- If such a value is found, return true as a duplicate exists within the specified distance and difference constraints.
- Store each element in its appropriate bucket in the map.
- If the window of inspection (determined by
k
) slides beyond the indexi
, remove the element that falls out of this range from the map using its bucket ID to maintain only relevant comparisons. - After checking all elements, return false if no such pair is found.
This implementation cleverly uses bucket sorting to reduce the complexity of checking each pair of indices in the naive approach. This ensures that each element is compared only with its immediate neighbors in a controlled bucket environment, optimizing the search for qualifying duplicate values. Adjusting the bucket storage dynamically as the index moves beyond k
keeps the memory usage efficient and operations swift.
class Solution:
def calculate_bucket_id(self, value, width):
return value // width
def check_nearby_dupe(self, elements, range_limit, difference):
if difference < 0:
return False
hash_map = {}
bucket_width = difference + 1
for index in range(len(elements)):
current_bucket = self.calculate_bucket_id(elements[index], bucket_width)
if current_bucket in hash_map:
return True
if (current_bucket - 1 in hash_map and abs(elements[index] - hash_map[current_bucket - 1]) < bucket_width):
return True
if (current_bucket + 1 in hash_map and abs(elements[index] - hash_map[current_bucket + 1]) < bucket_width):
return True
hash_map[current_bucket] = elements[index]
if index >= range_limit:
del hash_map[self.calculate_bucket_id(elements[index - range_limit], bucket_width)]
return False
The Python solution involves checking whether any two indices in an array differ by at most a given value difference
, and the values at those indices differing by at most range_limit
. This problem is approached using a bucketing method.
- Define a function
calculate_bucket_id
to compute the bucket number for each element in the array, based on the element's value and the bucket width. - In
check_nearby_dupe
, define a bucket width asdifference + 1
. - Create a dictionary to store the last value encountered in each bucket.
- Iterate through all elements in the array:
- Calculate the bucket for the current element.
- Check if the current bucket already exists in the dictionary. If yes, duplicate values are within the acceptable proximity, and return
True
. - Check the previous and the next buckets for proximity conditions, returning
True
if any condition matches. - Update the dictionary to store the current value in the current bucket.
- If the number of processed elements exceeds
range_limit
, remove the oldest element from the dictionary to maintain the range boundary.
- If no conditions are met throughout the loop, return
False
.
This method uses a sliding window technique mapping elements to buckets to ensure efficient look-ups and maintain the conditions given by the problem constraints.
No comments yet.