Problem Statement
Given an integer array nums
and two integer k
and t
, return true
if there are two distinct indicesi
and j
in the array such that:
abs(num[i] - nums[j]) ≤ t
, andabs(i - j) ≤ k
Otherwise, return false
.
Examples
Example 1:
Input: nums = [1, 2, 3, 1], k = 3, t = 0
Output: true
Explanation: nums[0] == nums[3], and |0 - 3| = 3 <= k
Also, |1 - 1| = 0 <= t
Example 2:
Input: nums = [1, 0, 1, 1], k = 1, t = 2
Output: true
Explanation: nums[2] == nums[3], |2 - 3| = 1 <= k, and |1 - 1| = 0 <= t
Example 3:
Input: nums = [1, 5, 9, 1, 5, 9], k = 2, t = 3
Output: false
Explanation: No such pair with both distance ≤ 2 and value diff ≤ 3
Constraints:
1 <= nums.length <= 10⁵
-2³¹ <= nums[i] <= 2³¹ - 1 (full 32-bit integer range)
0 <= k <= 10⁵
0 <= t <= 2³¹ - 1
Different Approach
1️⃣ Brute Force Approach
Intuition:
Compare each pair within k
distance and check value difference ≤ t
.
Code:
bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
for (int i = 0; i < nums.size(); ++i) {
for (int j = i + 1; j <= i + k && j < nums.size(); ++j) {
if (abs((long long)nums[i] - nums[j]) <= t)
return true;
}
}
return false;
}
Complexity Analysis:
- Time Complexity:
O(n * k)
- Space Complexity:
O(1)
2️⃣ Bucket Sort based Approach
Intuition:
- Divide the number line into buckets of size
valueDiff + 1
. If two numbers fall into the same bucket, they differ by ≤valueDiff
. - Also check adjacent buckets.
Code:
#include <unordered_map>
#include <vector>
#include <cmath>
using namespace std;
class Solution {
public:
bool containsNearbyAlmostDuplicate(vector<int>& nums, int indexDiff, int valueDiff) {
// Early exit: it's impossible to satisfy the condition if valueDiff is negative
if (valueDiff < 0) return false;
// Hash map to keep track of elements in their respective buckets
unordered_map<long long, long long> bucket;
// Width of each bucket: t + 1 to ensure value difference ≤ t for numbers in the same bucket
long long width = (long long)valueDiff + 1;
for (int i = 0; i < nums.size(); i++) {
long long num = (long long)nums[i];
// Compute the bucket ID (ensure negative numbers are handled correctly)
long long bucketId = num / width;
if (num < 0) bucketId--;
// Step 1: Check if there's already a number in the same bucket
if (bucket.find(bucketId) != bucket.end()) {
return true;
}
// Step 2: Check the left neighbor bucket
if (bucket.find(bucketId - 1) != bucket.end()) {
if (abs(bucket[bucketId - 1] - num) <= valueDiff) {
return true;
}
}
// Step 3: Check the right neighbor bucket
if (bucket.find(bucketId + 1) != bucket.end()) {
if (abs(bucket[bucketId + 1] - num) <= valueDiff) {
return true;
}
}
// Step 4: Place current number in its bucket
bucket[bucketId] = num;
// Step 5: Maintain a window of size indexDiff
// If size exceeds indexDiff, remove the number that's too old
if (i >= indexDiff) {
long long oldNum = (long long)nums[i - indexDiff];
long long oldBucketId = oldNum / width;
if (oldNum < 0) oldBucketId--;
bucket.erase(oldBucketId);
}
}
// No such pair found
return false;
}
};
Complexity Analysis:
- Time Complexity:
O(n)
- Space Complexity:
O(k)