220. Contains Duplicate III

这个和 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。。。

比较复杂,而且有多余空间。

原文地址:https://www.cnblogs.com/reboot329/p/6158936.html