Contains Duplicate III
Given an array of integers, find out whether there are two distinct indices i and j in the array such that the absolute difference between nums[i] and nums[j] is at most t and the absolute difference between i and j is at most k.
Example 1:
Input: nums = [1,2,3,1], k = 3, t = 0
Output: true
Example 2:
Input: nums = [1,0,1,1], k = 1, t = 2
Output: true
Example 3:
Input: nums = [1,5,9,1,5,9], k = 2, t = 3
Output: false
class Solution {
// O(nlogn) Solution
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
if (nums == null || nums.length < 2 || k < 1)
return false;
TreeSet<Long> set = new TreeSet<>();
for (int i = 0; i < nums.length; i++) {
long currNumber = (long) nums[i];
Long floor = set.floor(currNumber + t);
Long ceil = set.ceiling(currNumber - t);
// If there is a values with +-t range of our current number
if ((floor != null && floor >= currNumber) || (ceil != null && ceil <= currNumber))
return true;
set.add(currNumber);
// Maintaining a window size -> K
if (i >= k)
set.remove((long) nums[i - k]);
}
return false;
}
}
// O(n) Solution
public class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
if (k < 1 || t < 0)
return false;
// Bucketing means we map a range of values to the a bucket.
// So, as a rule of thumb, just make sure the size of the bucket is reasonable
// such that elements having the same bucket is immediately considered
// duplicates or duplicates must lie within adjacent buckets. So this actually
// gives us a range of possible bucket size, i.e. t and t + 1. We just choose it
// to be t and a bucket mapping to be num / t.
Map<Long, Long> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
// Another complication is that negative ints are allowed. A simple num / t just
// shrinks everything towards 0. Therefore, we can just reposition every element
// to start from Integer.MIN_VALUE.
long remappedNum = (long) nums[i] - Integer.MIN_VALUE;
long bucket = remappedNum / ((long) t + 1);
// Buckets of size -> T
// Now the number (if present) must be present in current bucket OR
// previous bucket OR the next bucket
if (map.containsKey(bucket) || (map.containsKey(bucket - 1) && remappedNum - map.get(bucket - 1) <= t)
|| (map.containsKey(bucket + 1) && map.get(bucket + 1) - remappedNum <= t))
return true;
// Maintaining a window size -> K
if (map.entrySet().size() >= k) {
long lastBucket = ((long) nums[i - k] - Integer.MIN_VALUE) / ((long) t + 1);
map.remove(lastBucket);
}
map.put(bucket, remappedNum);
}
return false;
}
}
Last updated