Contains Duplicate III Leetcode

Given an array of integers, find out whether there are two distinct indices i and j in the array such that the absolute difference between nums[i] and nums[j] is at most t and the absolute difference between i and j is at most k.

 

这道题做的还真的不容易。。。不过也算部分了解bucket sort了吧,只是还不熟练以后需要回顾。

主要思想是把所有的数分成t + 1个bucket,用num[i] / (t + 1)就可以得出这个数应该所在的bucket,放进去。这样距离为t的数字肯定在同个bucket或者相邻的bucket。

当hashmap的size大于等于k的时候,说明index距离已经大于k,这个时候要remove最原始的数。

注意:

1.相邻的bucket不一定就相距t所以要检查,所以value不可以放index要放resize之后的数。

2.bucket.size() >= k要有等号,因为这个if在前一个if后面,数字已经判断过,所以包含等号,一定要注意一下。

3.t<0 false, k <= 0 false;

4.注意边界溢出的问题。

public class Solution {
    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
        if (nums == null || nums.length == 0 || t < 0 || k < 1) {
            return false;
        }
        Map<Long, Long> bucket = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            long resize = (long) nums[i] - Integer.MIN_VALUE;
            long residual = resize / ((long) t + 1);
            if (bucket.containsKey(residual) || (bucket.containsKey(residual + 1) && bucket.get(residual + 1) - resize <= t
            || (bucket.containsKey(residual - 1) && resize - bucket.get(residual - 1) <= t))) {
                return true;
            }
            if (bucket.size() >= k) {
                long last = (long) nums[i - k] - Integer.MIN_VALUE;
                long r = last / ((long) t + 1);
                bucket.remove(r);
            }
            bucket.put(residual, resize);
        }
        return false;
    }
}

 这个题还可以用treeset做,treeset的话时间复杂度是O(nlgk)因为treeset add, remove,查找都是logn的时间复杂度。

again,注意越界。

public class Solution {
    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
        if (nums == null || nums.length == 0 || t < 0 || k < 1) {
            return false;
        }
        TreeSet<Long> ts = new TreeSet<>();
        for (int i = 0; i < nums.length; i++) {
            Long floor = ts.floor((long) nums[i]);
            Long ceil = ts.ceiling((long) nums[i]);
            if ((floor != null && nums[i] - floor <= t) || (ceil != null && ceil - nums[i] <= t)) {
                return true;
            }
            if (i >= k) {
                ts.remove((long) nums[i - k]);
            }
            ts.add((long)nums[i]);
        }
        return false;
    }
}

时隔几个月又来做这道题还是做不利索,而且做复杂了。。。但是这样是可以work的。

public class Solution {
    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
        if (k < 0 || t < 0 || nums == null) {
            return false;
        }
        Map<Long, Map<Integer, Integer>> hm = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            long d = nums[i] / (t + 1);
            Map<Integer, Integer> temp = hm.getOrDefault(d, new HashMap<>());
            if (!hm.containsKey(d)) {
                hm.put(d, temp);
            }
            if (checkExist(hm.getOrDefault(d, null), k, t, nums, i) || checkExist(hm.getOrDefault(d - 1, null), k, t, nums, i) || checkExist(hm.getOrDefault(d + 1, null), k, t, nums, i)) {
                return true;
            }
            temp.put(nums[i], i);
            
        }
        return false;
    }
    private boolean checkExist(Map<Integer, Integer> hm, int k, int t, int[] nums, int i) {
        if (hm == null) {
            return false;
        }
        for (int key : hm.keySet()) {
            long trans = (long) key;
            long v = (long) nums[i];
            if (Math.abs(trans - v) <= t && i - hm.get(key) <= k) {
                return true;
            }
        }
        return false;
    }
}

其实没必要在hashmap里面存list,存最近的就可以了,和之前的一样。而且一个bucket里面的肯定符合要求,就不用check了。直接除以(t+1)的话,落在同一个bucket的数字,余数是从0到t,他们之间的差最多是t,所以不用检查。但有一点例外,就是有的时候负数和正数除以一个数可能落在相同的bucket但是相差的很多。比如-3,3,t = 4的时候。这个时候要么检查一下想减是不是小于等于t,要么就把他们都变成正数。

经实验证明都变成正数比较快。

还有一个教训是,只要涉及到减法加法之类的过程,哪怕是加一,也得考虑边界溢出。。。

public class Solution {
    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
        if (k < 1 || t < 0 || nums == null) {
            return false;
        }
        
        Map<Long, Long> hm = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            long resize = (long) nums[i] - Integer.MIN_VALUE;
            long n = resize / ((long) t + 1);
            if (hm.containsKey(n) || (hm.containsKey(n - 1) && Math.abs(hm.get(n - 1) - nums[i]) <= t) || (hm.containsKey(n + 1) && Math.abs(hm.get(n + 1) - nums[i]) <= t)) {
                return true;
            } else {
                hm.put(n, (long) nums[i]);
            }
            if (hm.size() > k) {
                hm.remove(((long) nums[i - k] - Integer.MIN_VALUE) / ((long)t + 1));
            }
        }
        return false;
    }
}

 

我严重怀疑当初刷题的时候有没有理解这道题目。。。还是值得好好研究的,坑好像很多的样子。。。

posted @ 2017-02-22 10:22  璨璨要好好学习  阅读(150)  评论(0编辑  收藏  举报