package leetcode;
import java.util.TreeMap;
public class Solution220 extends Solution {
@Override
public void test() {
int[] nums = {0,10,22,15,0,5,22,12,1,5};
int k = 3, t = 3;
// int[] nums = {3,6,0,2};
// int k = 2, t = 2;
System.out.println(containsNearbyAlmostDuplicate(nums, k, t)); //二分法 // time limit exception
System.out.println(helper2(nums, k, t)); // 使用treeMap //AC
}
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
return helper(nums, 0, nums.length - 1, k, t);
}
/*
使用合并排序的思想,对nums进行二分,然后合并时比较两个部分的连接处是否满足条件:Math.abs(nums[i]-nums[j]) < t && i - j < k
结果:out time limit
*/
private boolean helper(int[] nums, int start, int end, int k, int t){
if(start >= end) return false;
int mid = start + (end - start) / 2;
if (helper(nums, start, mid, k, t)) {
return true;
}
if (helper(nums, mid+1, end, k, t)) {
return true;
}
return isExists(nums, mid + 1, mid + k <= end ? mid + k : end, k, t);
}
private boolean isExists(int[] nums, int start, int end, int k, int t){
for(int i = start; i<=end; i++){
int j = i - k < 0 ? 0 : i - k;
while(j < i){
if(Math.abs((long) nums[i] - (long) nums[j]) <= t){
return true;
}
j++;
}
}
return false;
}
/*
借助TreeMap的方法--ceilingKey()和floorKey(),快速确定滑动当前值所需要的范围。
假设 遍历nums,index = i;
当t==0时,也就是说需要找到之前数组中一个与当前数值nums[i]相同的值,直接查看map中是否有满足条件的值;
当t!=0时,借助TreeMap的两个方法,可以快速的定位当前值nums[i]满足题干要求的范围(-t <= nums[i] - x <= t)且在map存在的值,x属于[l, h],
其中,l是在map中满足大于nums[i]-t的最小值,h是在map中满足小于nums[i]+t的最大值,然后判断l和h对于nums[i]是否满足条件(<=t)
*/
private boolean helper2(int[] nums, int k ,int t){
if(nums.length < 1 || k < 1 || t < 0) return false;
TreeMap<Long, Integer> map = new TreeMap<>();
map.put((long) nums[0], 0);
for(int i=1; i<nums.length; i++){
long num = (long) nums[i];
if(t == 0){
if (map.containsKey(num) && i - map.get(num) <= k) {
return true;
}
map.put(num, i);
}else {
Long l = map.ceilingKey(num - (long) t);
Long h = map.floorKey(num + (long) t) ;
if(l != null && h != null && (Math.abs(num - l) <= t|| Math.abs(num - h) <= t)) {
int left = map.get(l);
int right = map.get(h);
if(i - left <= k || i - right <= k){
return true;
}
}
map.put(num, i);
}
}
return false;
}
}