leetcode220. 存在重复元素 III(中等,难题)

本文介绍了一种高效算法,利用滑动窗口和有序集合(O(nlogn))的优化版本,将查找附近几乎重复数字的时间复杂度降低到O(n)。通过分桶技巧减少查找次数,适用于解决数组中相近元素的存在性判断问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
思路:滑窗 +有序集合 O(nlogn)
具体思路:维护一个长度为k+1,abs(nums[i] - nums[j]) <= t的窗口。
如何判断在集合中存在[nums[i] - t, nums[i] + t]的元素呢?
找到大于等于nums[i] - t的最小元素,如果该元素小于等于 nums[i] + t,则为true

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

易错点:
1:abs(i - j) <= k是长度为k+1的滑窗,不是长度为k的滑窗。
2:固定滑窗应该先删除左端,再添加右端,因为当右端和左端相等时,就把右端删掉了。

思路二(优化了思路一) O(n)
思路一主要耗时在查找窗口内是否存在[nums[i] - t, nums[i] + t]的元素,可以用分桶的思想优化
每个桶放t + 1的元素,nums[i] / (t + 1) 得到桶的编号,假设t = 3,除以t+1 = 4。
因此桶的编号与对应元素的对应关系为:
1:[4,7]
0:[-3, 3]
-1:[-4,-7]
发现0号桶超过了t + 1个元素。
怎么解决呢?当nums[i]为负数时,桶编号计算公式为:(nums[i] + 1) / (t + 1) - 1。
这样的话:
1:[4,7]
0:[0, 3]
-1:[-4,-1]
成功解决了这个问题。
因此桶编号计算公式为:
nums[i]大于等于0时,buget = nums[i] / (t + 1) 。
否则:buget = (nums[i] + 1) / (t + 1) - 1

在一个桶中,return true,否则看一下隔壁桶中的元素是否与该元素的距离小于等于t(中间间隔有桶的距离一定大于t + 1)

class Solution {
public:
   unordered_map<long long, long long> hash;//桶编号->val 
    long long getindex(int n, int t) {
        return n >= 0 ? n / (t + 1ll) : (n + 1) / (t + 1ll) - 1; // 
    }
    bool judge(int num, int t) {
        long long buget = getindex(num, t);  
        if (hash.count(buget)) return true;
        if (hash.count(buget - 1) && abs(hash[buget - 1] - num) <= t) return true;
        if (hash.count(buget + 1) && abs(hash[buget + 1] - num) <= t) return true;  //
        return false;
    }  
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {// long long
         
        int n = nums.size(), l = 0;
        for (int r = 0; r < n; ++r) {
            if (r >= k + 1) hash.erase(getindex(nums[l++], t));
            if (judge(nums[r], t)) return true;
            hash[getindex(nums[r], t)] = nums[r];
        }
        return false;
    }
};

易错点
1:计算buget时,t+1可能会越界int-> t + 1ll
hash.count(buget - 1)可能会越界int->hash键为long long
abs(hash[buget + 1] - num)可能会越界int->hash值为long long

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值