[LeetCode]Contains Duplicate

题目:Contains Duplicate

给定整数数组,查找数组是否包含任何重复项。 如果数组中的任何值至少出现两次,则函数应返回true,如果每个元素都不同,则返回false。

思路:

可以使用桶排序的思想来,遍历所有元素,通过元素值直接访问标志,当第一次遇到则设标志,第二次遇到就跳出循环。

但是,这样空间复杂度很高,int有32位需要2^32byte;那么就可以考虑使用map;

其实只需要知道有没有重复元素就可以,不一定要找到,可以有更简单的方法;使用set,将数组元素放入set,有重复元素只会存放一遍,最后比较长度就能知道有没有重复。

bool LeetCode::containsDuplicate(vector<int>& nums){
    set<int>nondup(nums.begin(),nums.end());//保存所有所有元素一次,如果有重复则只保存一次
    return nondup.size() < nums.size();//有重复长度变短
}

题目:Contains DuplicateII

这次是找数组的k个元素中是否有重复。

思路:

和上面类似,只是不需要整个数组,只顺序选其中k个元素。

bool LeetCode::containsNearbyDuplicate(vector<int>& nums, int k){
    if (k >= nums.size() || nums.size() < 2){
        set<int>nondup(nums.begin(), nums.end());//保存所有所有元素一次,如果有重复则只保存一次
        return nondup.size() < nums.size();//有重复长度变短
    }
    auto head = nums.begin();
    auto tail = nums.begin() + k + 1;
    set<int>nondup(head, tail);
    while (tail != nums.end() && nondup.size() == k + 1){
        auto pos = nondup.find(*head);
        nondup.erase(pos);
        nondup.insert(*tail);
        ++head;
        ++tail;
    }
    if (nondup.size() <= k)return true;
    return false;
}

题目:Contains DuplicateIII

这次是找数组的k个元素中是否有差的绝对值不超过的t的2个以上的元素。

思路:

知道使用lower_bound函数就能很快做出来,可以通过lower_bound找到set中满足x >= nums[i] - t的下界,这样就可以按照上面的思路来解决。

bool LeetCode::containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t){
    set<long long>nondup;
    long long tL = t;
    for (size_t i = 0; i < nums.size();++i){
        if (i > k)nondup.erase(nums.at(i - k - 1));//k个元素以上时,每次删除第一个
        auto pos = nondup.lower_bound(nums.at(i) - t);//找到x >= nums[i] - t的下界
        if (pos != nondup.end() && *pos - nums.at(i) <= t)return true;//检测x <= nums[i] + t的上界
        nondup.insert(nums.at(i));//插入新的元素
    }
    return false;
}

思路2:

要求差的绝对值<=t。可以用这样的算法来确定:

假设有m和n满足上面的要求,则m/t = n/t或者m/t = n/t + 1或者m/t = n/t - 1;

当n = k*t,m = k*t - a(0 < a < t)时,m/t = n/t - 1;

这样就能按照前面的思路来求解,但是要注意一些特殊情况:

1.负数的情况,可以减去MIN_INT;

2.可能会溢出,使用long long类型;

3.t < 0或k<1的情况。

bool LeetCode::containsNearbyAlmostDuplicate2(vector<int>& nums, int k, int t){
    if (k < 1 || t < 0) return false;
    if (nums.size() < 2)return false;
    map<long long, long long>nondup;
    int MIN_INT = -2147483647 - 1;//不能直接将写-2147483648,因为便一起会先将2147483648转成int,再取负然后赋值
    long long tL = (long long)t + 1;
    for (size_t i = 0; i < nums.size(); ++i){
        long long value = ((long long)nums.at(i) - MIN_INT);
        long long bucket = value / tL;
        auto pre = nondup.find(bucket - 1);//n = k*tL m = k*tL - a;(0 < a < t)
        auto post = nondup.find(bucket + 1);//n = k*tL m = k*tL + a;(0 < a < t)
        if (nondup.find(bucket) != nondup.end() || (pre != nondup.end() && value - pre->second <= t) || (post != nondup.end() && post->second - value <= t))return true;
        if (i >= k){
            long long temp = ((long long)nums.at(i - k) - MIN_INT) / tL;
            nondup.erase(temp);//k个元素以上时,每次删除第一个
        }
        nondup[bucket] = value;//插入新的元素,通过n/(t+1)使t的间隔消失
    }
    return false;
}