力扣(LeetCode)220. 存在重复元素 III(C++)

滑动窗口+有序集合

维护滑动窗口,向右扩大右窗口,新数加入有序集合,题目要求abs(nums[i] - nums[j]) <= t ,找两数之差的绝对值小于t,相当于在窗口里找大小尽可能接近的两个数,固定其中一个数(新数),枚举窗口的数,得到另一个数。在有序集合里,可以二分优化枚举,找窗口内,大于等于新数的第一个数,位置x,在有序集合里,小于新数的第一个数的位置是x-1 。这两个数,就是窗口内最接近新数的数。判断abs(*x - nums[j]) <= tabs(*(x-1) - nums[j]) <= t 即可。

提示 : 窗口最大长度 k + 1 k+1 k+1 ,超过这个长度时,需要删除左窗口的值,向右缩小左窗口。

提示 : 使用有序集合的原因:利用有序集合 l o g n logn logn 时间进行插入、删除、查询操作,降低枚举窗口内元素的时间瓶颈。

提示 : 往有序集合里加入无穷大的哨兵,避免边界问题(空集合查询)。

题目描述

力扣(LeetCode)220. 存在重复元素 III(C++)_第1张图片

核心代码
class Solution {
public:
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
        typedef long long LL;
        set<LL> S;
        S.insert(1e18),S.insert(-1e18);
        for(int i = 0,j = 0;j<nums.size();j++){
            if(j-i>k) S.erase(S.find(nums[i++]));
            auto x = S.lower_bound(nums[j]);
            if(abs(*(x--) - nums[j])<=t) return true;
            if(abs(*x - nums[j])<=t) return true;
            S.insert(nums[j]);
        }
        return false;
    }
};
  1. 时间复杂度 : O ( n × l o g ( m i n ( n , k ) ) ) O(n\times log(min(n,k))) O(n×log(min(n,k))) n n n 是数字数量,遍历数字的时间复杂度 O ( n ) O(n) O(n) ,维护滑动窗口(有序集合),插入删除和查询的时间复杂度都是 O ( l o g ( m i n ( n , k ) ) ) O(log(min(n,k))) O(log(min(n,k))) ,二者是乘积关系,时间复杂度 O ( n × m i n ( l o g ( n , k ) ) ) O(n\times min(log(n,k))) O(n×min(log(n,k)))
  2. 空间复杂度 : O ( m i n ( n , k ) ) O(min(n,k)) O(min(n,k)) ,滑动窗口的空间复杂度 O ( m i n ( n , k ) ) O(min(n,k)) O(min(n,k))
AC

力扣(LeetCode)220. 存在重复元素 III(C++)_第2张图片

致语
  • 理解思路很重要!
  • 欢迎读者在评论区留言,墨染看到就会回复的。

你可能感兴趣的:(墨染leetcode,leetcode,c++,算法,红黑树,滑动窗口)