package com.anuragkapur.leetcode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author anuragkapur
*/
public class ContainsDuplicateIII {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
//return solution1(nums, k, t);
if (nums == null || nums.length < 2 || k <= 0 || t < 0) {
return false;
}
Map<Integer, Bucket> bucketMap = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int bucketKey = getBucketKey(nums[i], t);
// check if bucket exists
if (bucketMap.containsKey(bucketKey)) {
// check each pair in bucket
List<Pair> pairs = bucketMap.get(bucketKey).pairs;
for(Pair pair : pairs) {
int diff = Math.abs(nums[i] - pair.num);
if (i - pair.index <= k && diff <= t && diff >= 0) {
return true;
}
}
pairs.add(new Pair(nums[i], i));
} else {
List<Pair> pairs = new ArrayList<>();
pairs.add(new Pair(nums[i], i));
Bucket bucket = new Bucket();
bucket.pairs = pairs;
bucketMap.put(bucketKey, bucket);
}
// check adjoining buckets too
if (existsInBucket(bucketMap, bucketKey-1, i, nums[i], k, t)) {
return true;
}
if (existsInBucket(bucketMap, bucketKey + 1, i, nums[i], k, t)) {
return true;
}
}
return false;
}
private boolean existsInBucket(Map<Integer, Bucket> bucketMap, int bucketKey, int i, int num, int k, int t) {
if (bucketMap.containsKey(bucketKey)) {
// check each pair in bucket
List<Pair> pairs = bucketMap.get(bucketKey).pairs;
for (Pair pair : pairs) {
if (i - pair.index <= k && Math.abs(num - pair.num) <= t) {
return true;
}
}
}
return false;
}
private class Pair {
int num;
int index;
Pair(int num, int index) {
this.num = num;
this.index = index;
}
}
private class Bucket {
List<Pair> pairs;
}
private int getBucketKey(int num, int t) {
if (t == 0) {
return num;
}
return num / (t+1);
}
/**
* Running time: O(n*k)
* Space complexity: O(1)
*
* @param nums
* @param k
* @param t
* @return
*/
private boolean solution1(int nums[], int k, int t) {
if (nums == null || nums.length < 2) {
return false;
}
for(int i=0; i<nums.length; i++) {
for(int j=i+1; j<nums.length && j<=i+k; j++) {
if(Math.abs(nums[i] - nums[j]) <= t) {
return true;
}
}
}
return false;
}
}