220. Contains Duplicate III

下标间距<=k,立马就想到滑动窗口,维护一个大小为k的区间。

方法一:

对于新的数,维护区间大小的同时,需要判断该区间中是否存在 [num-t, num+t] 的数字。由于需要根据大小查找,可以利用大小为 k 的 set 作为维护的区间,set 是有序的,因此可以调用 lower_bound 找到第一个大于等于 num-t 的数字。只要判断该数是否小于等于 num+t 即可(因为只要有一个就行了)。

用 set 是没有问题的,假设 k 区间有重复的元素,重复的元素差值为0,一定<t,一定会返回 true,因此即使有重复元素也可以处理。只不过用 set 的话,erase 的时候不能用 s.size()>k 作为判断条件。本题用multiset做当然也是可以的。

注意一下 int 会越界,要用 long(真恶心)。

class Solution {
public:
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
        set<long> s;
        for (int i=0;i<nums.size();++i){
            long num=nums[i];
            if (i>k) s.erase(nums[i-k-1]);
            auto low=s.lower_bound(num-t);
            if ( low!=s.end() && *low<=num+t ) return true;
            s.insert(num);
        }
        return false;
    }
};

 

方法二:

利用类似桶排序的方法,将桶作为窗口(上述方法是用set作为窗口)。每个桶的宽度设为t+1,即将数组的数根据大小映射到 ... [0,t],[t+1,2t+1],... 中,只有当两个数在同一个桶中或在相邻的桶中,这两个数差的绝对值才会小于等于t。因此,用这种方法,循环中对于每个数,只要判断这个数本身桶中有没有数,或相邻两个桶中有没有符合要求的数,因此时间复杂度是O(n)。

和桶排序不同的是,每个桶中最多只有一个元素,这是因为如果一个桶之前有一个数,后面的数也在该桶中的话,直接就return true了。因此桶可以直接用hash表来建立。

class Solution {
public:
    long getBucketId(long num, long w){
        return num<0 ? (num+1)/w-1 : num/w;
    }
    
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
        if (t<0) return false;
        unordered_map<long,long> buckets;
        long width=(long)t+1;
        
        for (int i=0;i<nums.size();++i){
            if (i>k) buckets.erase(getBucketId(nums[i-k-1],width));
            long num=nums[i];
            long id=getBucketId(num,width);
            if (buckets.count(id)) return true;
            if (buckets.count(id-1) && abs(num-buckets[id-1])<width) return true;
            if (buckets.count(id+1) && abs(num-buckets[id+1])<width) return true;
            buckets[id] = num;
        }
        return false;
    }
};

 

posted @ 2018-06-09 14:39  約束の空  阅读(111)  评论(0)    收藏  举报