leetcode刷题记录2021年4月17日

220. 存在重复元素 III

给你一个整数数组 nums 和两个整数 k 和 t 。请你判断是否存在 两个不同下标 i 和 j,使得 abs(nums[i] - nums[j]) <= t ,同时又满足 abs(i - j) <= k 。
如果存在则返回 true,不存在返回 false。

示例 1:
输入:nums = [1,2,3,1], k = 3, t = 0
输出:true

示例 2:
输入:nums = [1,0,1,1], k = 1, t = 2
输出:true

示例 3:
输入:nums = [1,5,9,1,5,9], k = 2, t = 3
输出:false

提示:
0 <= nums.length <= 2 * 104
-231 <= nums[i] <= 231 - 1
0 <= k <= 104
0 <= t <= 231 - 1

暴力解肯定是会超时的

思路

像这种找两个下标的,一般情况下 ,第一步都是利用给出的条件把它化成查找一个下标的形式,要满足abs(i - j) <= k,这里有两种思路,一个是哈希表,一个是红黑树,为什么要用这两种呢?可以从一开始像,如果是暴力解法,要做的就是对每一个元素查找周围的2k+1个元素,也就是O(nk),这里两种方法都遵循一个思路,就是减少k,也缩短下面的过程:
给定下标i,在[i-k,i+k]中判断是否存在[nums[i]-t,nums[i]+t]的值

红黑树

维护一个红黑树,包含i之前的k个元素(砍掉一半,后面的由后面的元素来判断),查找第一个大于等于nums[i]-t的元素是不是小于nums[i]+t就行了,因为红黑树每次查找的时间复杂度在O(lgn)所以总的时间复杂度为O(nlgn).

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

哈希表

维护一个哈希表,包含i之前的k个元素。
利用了桶排序的思想,设置桶的大小为t+1,这样每次查找元素,只要找当前所应归属的桶和周围两个就行了,对每一个元素,都在哈希表中查找当前桶和周围的两个,时间复杂度为O(1),总的时间复杂度为O(n)。

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

总结

主要学习到的是对数据结构的解构和应用,像是红黑树和哈希表,都是非常高效的查找元素的方法,可以将问题解构吗,然后使用特定的数据结构去优化它。c++中对应这两者的是set和unordered_map,这类题思路可能很直接,但是,要在如何将问题转化到特定的数据结构上比较花心思。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值