1.题目描述
给你一个整数数组
nums
和两个整数indexDiff
和valueDiff
。找出满足下述条件的下标对
(i, j)
:
i != j
,abs(i - j) <= indexDiff
abs(nums[i] - nums[j]) <= valueDiff
如果存在,返回
true
;否则,返回false
。示例 1:
输入:nums = [1,2,3,1], indexDiff = 3, valueDiff = 0 输出:true 解释:可以找出 (i, j) = (0, 3) 。 满足下述 3 个条件: i != j --> 0 != 3 abs(i - j) <= indexDiff --> abs(0 - 3) <= 3 abs(nums[i] - nums[j]) <= valueDiff --> abs(1 - 1) <= 0示例 2:
输入:nums = [1,5,9,1,5,9], indexDiff = 2, valueDiff = 3 输出:false 解释:尝试所有可能的下标对 (i, j) ,均无法满足这 3 个条件,因此返回 false 。提示:
2 <= nums.length <= 105
-109 <= nums[i] <= 109
1 <= indexDiff <= nums.length
0 <= valueDiff <= 109
2.解题思路
使用分桶的思想,把每一个元素nums[i] / (valueDiff+1)的值作为桶id,进行分桶,这样能保证所有符合valueDiff范围的元素一定是位于相同的桶中或者是相邻的桶中;
于是,只需要按照indexDiff为界进行元素分桶,如果当前元素对应的桶id已经有元素或者相邻桶中有与他差值小于等于valueDiff的元素时,就返回true,否则将该元素加入桶中,如果当前下标已经大于等于indexDiff,就要弹出nums[i-indexDiff]元素对应的桶。如果遍历结束都没有返回true,说明不存在符合题意的条件,返回false
3.代码实现
class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int indexDiff, int valueDiff) {
Map<Long,Long> map = new HashMap<>();
long w = (long) valueDiff + 1;
for (int i = 0; i < nums.length; i++) {
long id = getId(nums[i],w);
if (map.containsKey(id)) {
return true;
}
if (map.containsKey(id - 1) && Math.abs(map.get(id - 1) - nums[i]) < w) {
return true;
}
if (map.containsKey(id + 1) && Math.abs(map.get(id + 1) - nums[i]) < w) {
return true;
}
map.put(id,(long)nums[i]);
if (i >= indexDiff) {
map.remove(getId(nums[i-indexDiff],w));
}
}
return false;
}
public long getId(long x, long w) {
if (x >= 0) {
return x / w;
}
return (x + 1) / w - 1;
}
}