问题描述:
- 给定一个整数数组
nums
和两个整数 k
和 t
,判断是否存在两个不同下标 i
和 j
,使得 abs(nums[i] - nums[j]) <= t
,同时又满足 abs(i - j) <= k
。
- 如果存在则返回
true
,不存在返回 false
。 -2^{31} <= nums[i] <= 2^{31} - 1
。
核心思路:
- 该题的基础解法就是滑动数组 + 有序哈希表(红黑树)。
- 滑动窗口就是用于维护固定长度为
k
的窗口。 - 有序哈希表
ss
是为了访问到当前数值 x
时,方便找到窗口中满足 [x-t, x+t]
的第一个数,因为只需要找到一个数就可,所以可以直接用二分搜索。
- 具体实现上:
- 可以直接调用
ss
的 lower_bound
函数找到有序集合中第一个大于等于 x-t
的位置,即调用 ss.lower_bound(x-t)
。【又因为 x
有可能为 INT_MIN
,所以无法直接将 x-t
传给函数,而是传入 max(nums[i], INT_MIN+t) - t
】 - 找到第一个大于等于
x-t
的位置后,再判断该值是否小于等于 x+t
即可。【同理,x
取值可能为 INT_MAX
,所以不可以直接相加,即 x+t = min(nums[i], INT_MAX-t) + t
】
代码实现:
class Solution
{
public:
bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t)
{
set<int> ss;
int l = 0, r = 0;
int m = nums.size();
while(r < m)
{
auto iter = ss.lower_bound(max(nums[r], INT_MIN + t) - t);
if(iter != ss.end() and *iter <= min(nums[r], INT_MAX - t) + t)
return true;
ss.insert(nums[r++]);
if(ss.size() > k)
ss.erase(nums[l++]);
}
return false;
}
};