思路:
- 用哈希表来模拟桶,哈希表的键为桶的
id
,值为数组中元素的值,哈希表中只存放当前元素以及前k
个元素; - 遍历哈希表,计算每个元素的桶
id
,将其放入对应的桶中; - 若桶中已经有元素,说明已存在两个数差值小于
t
,直接返回true
; - 若相邻的桶中有元素,且与当前元素的绝对差值小于
t
,也返回true
; - 删除下标范围不在
[max(0, i - k), i]
内的桶。
#define LL long long //本题会爆int,所以直接用long long
class Solution {
public:
bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
if (nums.empty()) return false;
unordered_map<LL, LL> hash;
//差值为 t 的两个数在数轴上间隔距离为 t + 1
LL bucketSize = t + 1LL;
for (int i = 0; i < nums.size(); ++ i)
{
LL num = nums[i] * 1LL;
LL id = getBucketID(num, bucketSize);
if ( hash.find(id) != hash.end()
|| hash.find(id - 1) != hash.end() && hash[id - 1] + t >= num
|| hash.find(id + 1) != hash.end() && hash[id + 1] - t <= num )
{
return true;
}
hash[id] = num; //将当前元素放入对应的桶中
if (i >= k) //删除对应 id 的桶
{
hash.erase(getBucketID(nums[i - k], bucketSize));
}
}
return false;
}
//计算桶id实质就是用当前数字除以 bucketSize 得到的商
LL getBucketID(LL num, LL bucketSize)
{
//如果当前数字为负数,需要特殊处理
return num >= 0 ? (num / bucketSize) : (num + 1) / bucketSize - 1;
}
};