Given an array of integers, find out whether there are two distinct indices i and j in the array such that the difference between nums[i] and nums[j] is at most t and the difference between i and j is at most k.
要求:|nums[i]-nums[j]|<=t,且|i-j|<=k,用hashmap就没意义了,因为不是找相同,而是找相近了。
tag提示binary search tree,而java中的tree容器有:TreeSet与TreeMap。其中,TreeSet是基于TreeMap实现的,底层使用红黑树,属于平衡二叉树。TreeSet保证基本操作(add,remove,contains)时间复杂度为O(logn),且内部元素有序。(hashmap不保证有序,且两次返回的顺序也不一定相同,但是它对于get与put操作能保证constant-time performance)
TreeSet<E>中的一些方法:(注意TreeSet中的元素时有序的)
ceiling(E e):大于等于e中的最小值
floor(E e): 小于等于e中的最大值
higher(E e)/lower(E e):大于/小于 e中的 最小/最大 的元素
first(): 返回最小的元素
last(): 返回最大的元素
正确的代码:
public class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
if(k<1 || t<0){
return false;
}
boolean result = false;
TreeSet<Integer> mySet = new TreeSet<Integer>();
for(int i=0; i<nums.length; i++){
Integer high = mySet.ceiling(nums[i]); //大于等于nums[i]的最小值
Integer low = mySet.floor(nums[i]); //小于等于nums[i]的最大值
if(high!=null && high<=t+nums[i] || low!=null && nums[i]<=t+low){
result = true;
break;
}
mySet.add(nums[i]);
if(i>=k){ //使set的大小始终小于等于k,起到滑动窗口的作用
mySet.remove(nums[i-k]);
}
}
return result;
}
}
注意,在上面的代码中:
if(high!=null && high-nums[i]<=t || low!=null && nums[i]-low<=t){
result = true;
break;
}
这样的写法不行,leetcode有个testcase是[-1,2147483647], 1, 2147483647。按上面的写法会发生溢出。。。
下面是有错的代码:(用map< nums[i], index >来记录已遍历过的值及其index,这种想法是可行的,但在本题的条件下,就得额外考虑一些东西了)
public class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
if(k<1 || t<0){
return false;
}
boolean result = false;
TreeMap<Integer, Integer> myMap = new TreeMap<Integer, Integer>();
//找了很久,终于找到这段代码哪里错了。。。。
for(int i=0; i<nums.length; i++){ //[10,100,11,9],k=1,t=2,当循环到num[3]=9时,得low=null,high=<10,0>
Integer high = myMap.ceilingKey(nums[i]); //而非<11,2>,代码判断t满足,但是k不满足,从而result=false...
Integer low = myMap.floorKey(nums[i]);
if(high!=null && high<=t+nums[i] && i-myMap.get(high)<=k){
result = true; //故在上面的情况下,仅仅找到一个high就判断当前遍历的nums[i]能否返回true是不够的
break; //还要找到比high大的最小元素再判断,然后循环找下去,甚至当对元素间距k要求很松时,
} //可能得在map中找到所有比nums[i]大的元素判断
if(low!=null && nums[i]<=t+low && i-myMap.get(low)<=k){
result = true;
break;
}
myMap.put(nums[i], i);
}
return result;
}
}