这个和 I 、II 比不是一个级别的。。
I找数组里有没有重复的,用HashSet判定就行。
II是有没有重复,然后重复俩元素距离小于K。
用HashTable,KEY是元素,VALUE是坐标,遍历数组遇到存在于TABLE中的元素,返还那个元素的坐标,和当前比较,如果小于K,就TRUE;否则用当前元素的坐标替换原来的VALUE,保留最近的,如果最近的都大于K,那么之前的那些肯定更大于K。。
III,难度陡然上升。。。
用TreeSet,其中2个方程比较关键
1 floor(n)返还不小于n的最小元素
2 ceiling(n)返还不大于n的最大元素
TreeSet是滑动的窗口,里面是满足距离小于k的所有元素。
比如K是4 那么
8 1 2 3 4 9 5
——————————
——————————
————————————
横线就是窗口的变化
遍历到4的时候从 8 1 2 3里面找
遍历到9的时候从 1 2 3 4里面找
遍历到5的时候从 2 3 4 9里面找
找到时候因为所有值都满足K的要求,那么就看T就行了。
正常情况是遍历窗口里所有元素m,然后
Math.abs(m-nums[n]) <= t)
但是超时。然后我们只比较
大于当前元素里最小的 floor(nums[n]) - nums[n] <= t
小于当前元素里最大的 nums[n] - ceiling(nums[n]) <= t
有一个满足就RETURN TRUE
否则当前元素进入窗口。
然后如果窗口大于K,把第一个元素拿出去。。
//difference between i and j is at most k
//nums[i] and nums[j] is at most t
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t)
{
//if(nums.length < 2) return false;
if(k <= 0) return false;
if(t < 0) return false;
//if(t == 0) return false;
TreeSet<Long> set = new TreeSet<Long>();
for(int n = 0; n < nums.length;n++)
{
Long tempVal = new Long(nums[n]);
if( (set.floor(tempVal) != null && tempVal - set.floor(tempVal) <= new Long(t)) ||
(set.ceiling(tempVal) != null && set.ceiling(tempVal) - tempVal <= new Long(t) ) )return true;
set.add(tempVal);
if(n >= k) set.remove(new Long(nums[n-k]));
}
return false;
}
好鸡巴难。。
判定RETURN TRUE的2个情况,用||可以通过,换成2个IF xxx renturn true;
if xxx return true;
超时,醉了。。
然后EDGE CASE,K < 1 FALSE 因为距离必须大于1,0的话就是相同元素,不满足distinct。小于0的话就很无聊,没有负距离,感觉这种EDGE CASE是为了测验而测验,这个题的精髓明显是前面的逻辑关系。。
另一个EDGE CASE T < 0一样,绝对值不能小于0。。这俩EDGE CASE毁了好心情。。
二刷。
这个傻逼题。。
Edge cases太多了。
维持滑窗,滑窗用treeSet这个数据结构,主要为了lgN时间找到需要的2个边界值。
不小于Target的最小值;
不大于Target的最大值。。
Time: O(n lg K)
Space: O(k)
public class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
if (k <= 0) return false;
if (t < 0) return false;
TreeSet<Long> window = new TreeSet<>();
for (int i = 0; i < nums.length; i++) {
long temp = (long)nums[i];
if (window.floor(temp) != null && temp - window.floor(temp) <= (long)t) {
return true;
}
if (window.ceiling(temp) != null && window.ceiling(temp) - temp <= (long)t) {
return true;
}
window.add(temp);
if (i >= k) {
window.remove((long)nums[i - k]);
}
}
return false;
}
}
另一种做法是排序,然后用个MAP之类的记录INDEX。。。
比较复杂,而且有多余空间。