Contains Duplicate III

update Sep 9, 2017 14:08

LeetCodearrow-up-right

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.

Basic Idea:

这道题其实是问在给定数组nums中,是否有一个window(size为k+1)使得window内有两个元素的绝对值差不大于 t;

思路 1:TreeSet 首先想到的思路是用 sliding window 的思路,每移动一次窗口,就扫描一遍窗口中的 k 个元素,看能否和刚进入的最右边元素满足要求,时间复杂度为O(n * min(k,n))。但是这么做显然太慢了。接下来就想到可以优化每次移动窗口后的比较过程,利用一个 TreeSet,这样每次的比较时间复杂度就从 O(k) 变成了 O(logk), 总的时间也变为了 O(n * min(logn, logk));

Java Code:

    class Solution {
        public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
            if (nums == null || nums.length < 2) return false;
            TreeSet<Integer> treeset = new TreeSet<>();
            int i = 0, j = 1;
            treeset.add(nums[0]);
            while (j < nums.length) {
                if (j - i > k) {
                    treeset.remove(nums[i]); // 窗口 left 右移,删去出去的num
                    i++;
                }
                if (treeset.ceiling(nums[j]) != null && Math.abs((long)treeset.ceiling(nums[j]) - (long)nums[j]) <= t)
                    return true;  //  check successor
                if (treeset.floor(nums[j]) != null && Math.abs((long)treeset.floor(nums[j]) - (long)nums[j]) <= t)
                    return true;  //  check predecessor
                treeset.add(nums[j]);
                j++;
            }
            return false;
        }
    }

思路 2:Bucket 每个 bucket 的size为 t,维持这个buckets,每次右边刚进入窗口的数 m,我们检查 m 所在bucket中是否有元素,若没有,则检查 m 所在bucket的左边和右边相邻有无元素即可。 时间: O(n)

Python Code:

update 2018-07-21 17:27:05

Update Bucket sort solution

思路如下:

  1. 先将input array normalize 为 最小值为 0 的数组;

  2. 用一个hashMap来存放buckets,bucket index = num / (t + 1)

  3. 保持 window size 为 k + 1,每次查看当前数字对应 bucket index 是否已有元素,若有,则该元素与当前数字的绝对值差一定小于等于 t,直接返回true;否则的话,查看 index - 1 和 index + 1 两个buckets,看其中的元素和当前数字的距离是否小于等于 t;