Description
You are given an integer array nums
and two integers indexDiff
and valueDiff
.
Find a pair of indices (i, j)
such that:
i != j
,abs(i - j) <= indexDiff
.abs(nums[i] - nums[j]) <= valueDiff
, and
Return true
if such pair exists or false
otherwise.
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.
Solution in Python
To solve the problem of finding whether there exists a pair of indices (i, j)
in the array nums
such that the following conditions are satisfied:
i != j
abs(i - j) <= indexDiff
abs(nums[i] - nums[j]) <= valueDiff
We can employ a strategy using a sliding window and a SortedSet
from the sortedcontainers
module. The SortedSet
allows us to efficiently manage a dynamic set of elements while keeping them sorted, which helps us quickly find the closest values to any element within the current window of size indexDiff
.
Steps to Solve the Problem:
- Initialize a
SortedSet
: This will be used to maintain the current window of elements in the array, where the window size is controlled byindexDiff
. - Iterate through the array
nums
:- For each element
nums[i]
, find the closest value in the current window that could potentially satisfy thevalueDiff
condition. - Check for potential matches both just smaller and just larger than the current element in the
SortedSet
. - If a valid match is found, return
True
. - Add the current element
nums[i]
to theSortedSet
. - Ensure that the
SortedSet
maintains a maximum size ofindexDiff
by removing the oldest element (i.e.,nums[i - indexDiff]
) when necessary.
- For each element
- If no valid pair is found during the iteration, return
False
.
from sortedcontainers import SortedSet
class Solution:
def containsNearbyAlmostDuplicate(self, nums, indexDiff, valueDiff):
# Create a SortedSet to maintain the current window of elements
window = SortedSet()
for i, num in enumerate(nums):
# Find the smallest element in the set that is >= nums[i] - valueDiff
pos = window.bisect_left(num - valueDiff)
# Check if such an element exists and is within the valueDiff constraint
if pos < len(window) and abs(window[pos] - num) <= valueDiff:
return True
# Add the current number to the set
window.add(num)
# Maintain the size of the window to be at most indexDiff
if i >= indexDiff:
window.remove(nums[i - indexDiff])
return False
Explanation:
- SortedSet:
- The
SortedSet
from thesortedcontainers
module is used because it allows us to maintain a dynamically sorted set of elements with efficient insertion, deletion, and lookup operations.
- The
- Window Management:
- The
window
set is used to keep track of the lastindexDiff
elements (or fewer at the beginning). As we iterate overnums
, we add the current element towindow
and remove the element that is outside the current window size.
- The
- Finding Close Values:
pos = window.bisect_left(num - valueDiff)
finds the smallest element inwindow
that is greater than or equal tonum - valueDiff
. This is crucial because it gives us a potential candidate for satisfying thevalueDiff
condition.- We then check if the difference between this candidate and
num
is withinvalueDiff
. If it is, we returnTrue
.
- Efficiency:
- The operations of adding, removing, and finding the closest element in the
SortedSet
are all logarithmic in complexity, making this approach efficient for large input sizes.
- The operations of adding, removing, and finding the closest element in the
Result:
The function returns True
if there exists a pair (i, j)
that satisfies all the given conditions. Otherwise, it returns False
. This approach effectively handles large arrays and the constraints provided.
Solution in Javascript
var containsNearbyAlmostDuplicate = function(nums, indexDiff, valueDiff) {
if (indexDiff <= 0) return false;
// Map that will serve as our TreeSet-like structure
const map = new Map();
for (let i = 0; i < nums.length; i++) {
let num = nums[i];
// Determine the bucket key for the current number
let bucket = Math.floor(num / (valueDiff + 1));
// Check if current bucket contains a duplicate within the range
if (map.has(bucket)) {
return true;
}
// Check neighboring buckets for values within the range
if (map.has(bucket - 1) && Math.abs(num - map.get(bucket - 1)) <= valueDiff) {
return true;
}
if (map.has(bucket + 1) && Math.abs(num - map.get(bucket + 1)) <= valueDiff) {
return true;
}
// Insert the number into its bucket
map.set(bucket, num);
// Maintain the size of the map to be at most indexDiff
if (map.size > indexDiff) {
// Remove the element that is out of the window
let oldBucket = Math.floor(nums[i - indexDiff] / (valueDiff + 1));
map.delete(oldBucket);
}
}
return false;
};
Solution in Java
import java.util.TreeSet;
class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int indexDiff, int valueDiff) {
if (nums == null || nums.length < 2 || indexDiff < 1) {
return false;
}
// TreeSet to maintain a sliding window of the last `indexDiff` elements
TreeSet<Long> set = new TreeSet<>();
for (int i = 0; i < nums.length; i++) {
long num = (long) nums[i]; // Cast to long to handle large numbers
// Check if there is a number in the set within the range [num - valueDiff, num + valueDiff]
Long floor = set.floor(num + valueDiff);
if (floor != null && floor >= num - valueDiff) {
return true;
}
// Add the current number to the set
set.add(num);
// Maintain the size of the set to be at most `indexDiff`
if (i >= indexDiff) {
set.remove((long) nums[i - indexDiff]);
}
}
// If no such pair was found, return false
return false;
}
}
Solution in C#
using System;
using System.Collections.Generic;
public class Solution {
public bool ContainsNearbyAlmostDuplicate(int[] nums, int indexDiff, int valueDiff) {
if (nums == null || nums.Length < 2 || indexDiff < 1) {
return false;
}
// SortedSet to maintain a sliding window of the last `indexDiff` elements
SortedSet<long> set = new SortedSet<long>();
for (int i = 0; i < nums.Length; i++) {
long num = (long) nums[i]; // Cast to long to avoid overflow issues
// Find the smallest element in the set that is greater than or equal to `num - valueDiff`
if (set.GetViewBetween(num - valueDiff, num + valueDiff).Count > 0) {
return true;
}
// Add the current number to the set
set.Add(num);
// Maintain the size of the set to be at most `indexDiff`
if (i >= indexDiff) {
set.Remove((long) nums[i - indexDiff]);
}
}
// If no such pair was found, return false
return false;
}
}