关于C++中对set和multiset进行二分查找 (LeetCode 220)

这篇博客分享了一种利用滑动窗口和二分查找的策略来解决LeetCode上的220.存在重复元素III问题。通过使用multiset实现高效查找,并讨论了如何处理集合大小、窗口移动以及元素插入和删除的细节,确保查找效率。文章强调了在C++中使用multiset内置的二分查找库函数的重要性,以及注意事项,如避免使用下标访问和正确使用erase函数。
摘要由CSDN通过智能技术生成

前言:今天碰到了一题关于滑动窗口+二分查找的题目,用C++做题时需要使用multiset,因此前来贴出模板,望能供大家参考。


题目

这里贴出原题:LC 220. 存在重复元素 III 供大家测试代码使用
在这里插入图片描述

题目解析: 本道题如果使用其他方法可能会将题目复杂化,但是如果使用滑动窗口却会非常直观:由于题目需要找两个下标不同的元素,所以我们可以将 n u m s [ 0 ] nums[0] nums[0] 插入集合后,枚举窗口右边界的下标 i ( i ∈ [ 1 , n − 1 ] ) i (i\in[1, n - 1]) i(i[1,n1]),同时当集合大小超过上限 k + 1 k+1 k+1 后,抹除窗口左边界元素即可。

代码:

class Solution {
public:
    using LL = long long;
    
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int w, int t) {
        if(w == 0)  return false;
        
        int n = nums.size();
        multiset<LL> s;
        
        s.insert(nums[0]);
        
        for(int i = 1; i < n; ++i){
            int v = nums[i];
            const auto& pos = s.lower_bound(v);
            
            if(pos != s.end() and abs(v - *pos) <= t)     return true;
            if(pos != s.begin() and abs(v - *(prev(pos, 1))) <= t)  return true;
                
            s.insert(v);
            if(i >= w){
                s.erase(s.find(nums[i - w]));
            }
        }
        
        return false;
    }
};

这里需要注意三点

  • 需要使用 multiset 自带的二分查找库函数才能够保证 O ( l o g n ) O(logn) O(logn) 的查找效率,使用 std 的二分查找库函数可能会导致查找效率退化至 O ( n ) O(n) O(n),原因有可能是 multiset 不支持按照下标访问.
  • 由于 multiset 不支持下标访问,所以访问前一个或者后一个迭代器的时候,可以使用 prev(pos, 1)/ next(pos, 1) 的方式,其中 pos 为红黑树迭代器.
  • 由于 multiset 的 erase(x) 函数会删除所有值为x的节点,因此采用s.erase(s.find(x));可以保证只删除一个.

以上结论对于C++中的 set 一样适用. 收!


参考文章:关于C++ STL中对于set使用lower_bound进行二分查找的效率问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值