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;
}
}