Leetcode 220. Contains Duplicate III

本文介绍了一种使用二叉搜索树解决寻找数组中接近重复项问题的方法。通过维护一个大小为k的滑动窗口,并利用set数据结构进行高效查找,确保在O(n log k)的时间复杂度内解决问题。

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

Given an array of integers, find out whether there are two distinct indices i and j in the array such that the absolute difference between nums[i] and nums[j] is at most t and the absolute difference between i and j is at most k.

s思路:
1. 看了提示,用binary search tree。用BST,在c++就是用set或map了,因为这两样就是用bst实现的。
2. 因为没有重复,所以不能用hash。坐标之差在一个范围内,我们可以每次只在这个范围内寻找数,比如:从左往右移动,当长度大于k,那么就把搜索区间的最左边删除,类似与two pointer的方法,只是这个窗口达到k后就不增加了;
3. 数据之差如何搞定呢?当然可以在窗口内双重循环找到所有数据之差然后判断是否存在一个数据差小于t,但这样复杂度就是o(k^2),由于没窗口每次移动一下,都要这样来一遍,所以总的复杂度o(nk^2),还是太大。
4. 主要的问题是:在k长的窗口内,是否存在|nums[i]-nums[j]|<=t的一对数据?由于数据是无序的,难道一定要遍历所有o(k^2)的可能吗?这几天都在说,要从无序中看出是否有序的可能,先不说马上能看到,但一定要有信念,不然真看不到,因为心里着急,气急败坏,没有信心嘛。
5. 先把上面的不等式展开:-t<=nums[i]-nums[j]<=t,继续处理:

nums[i]-t<=nums[j]<=nums[i]+t

注意看,这就和原来不一样了,我们假设i是从左往右遍历的当前的数的index,而j

//方法1:用set,
class Solution {
public:
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
        //
        set<long> ss;//bug:调试很久,刚开始用int,发现要做运算,极限case过不了,所以用long保护
        for(int i=0;i<nums.size();i++){
            if(i>k) ss.erase(nums[i-k-1]);    
            set<long>::iterator it=ss.lower_bound((long)nums[i]-t); //bug:只需要把其中之一转换成long即可
            if(it!=ss.end() && (*it)-nums[i]<=t) return true;
            ss.insert(nums[i]);
        }
        return false;
    }
};

//优化1:不用每次都把nums[i]转成long,考虑到两个数相加减,如果一个数是long,另一个是int,那么结果仍是long.所以不如把t转换成long,果然快一些!
class Solution {
public:
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
        //
        set<long> ss;
        long lt=t;
        for(int i=0;i<nums.size();i++){
            if(i>k) ss.erase(nums[i-k-1]);    
            set<long>::iterator it=ss.lower_bound(nums[i]-lt);  
            if(it!=ss.end() && (*it)-nums[i]<=lt) return true;
            ss.insert(nums[i]);
        }
        return false;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值