题目
剑指 Offer II 057. 值和下标之差都在给定的范围内
思路
由于这个题目关心的是差的绝对值小于或等于t
的数字,因此可以将数字放入若干大小为t+1
的桶
中
例如,将从0到t的数字放入编号为0的桶中,从t+1到2t+1的数字放入编号为1的桶中
这样做的好处是:
- 如果两个数字被放入同一个桶中,那么它们的差的绝对值一定小于或等于
t
- 如果桶
T
中之前没有数字,则再判断编号为T-1
和T+1
的这两个相邻的桶中是否存在与num的差的绝对值小于或等于t
的数字
- 因为其他桶中的数字与num的差的绝对值一定大于
t
,所以不需要判断其他的桶中是否有符合条件的数字
为什么桶大小为t+1?
- 如果桶大小
大于等于t+2
行不行?
-
不行,这样就无法做到桶中两个数的差值一定小于等于t
-
如果桶大小为
t
行不行?
-
行,但是在根据每个元素的值计算桶编号时,如果t为0,就会有除0异常的问题
-
如果桶大小
小于t
行不行?
- 不行,这样就无法做到当桶没有数字时,只检查相邻的两个桶
因此,最佳的桶大小为t+1
代码
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
Map<Integer,Integer> map = new HashMap<>();
for (int i = 0;i<nums.length;i++) {
int bucketID = getBucketID(nums[i], t + 1 );
if (map.containsKey(bucketID) ||
(map.containsKey(bucketID-1) && map.get(bucketID-1) + t >= nums[i]) ||
(map.containsKey(bucketID+1) && map.get(bucketID+1) - t <= nums[i])) {
return true;
}
map.put(bucketID,nums[i]);
if (i >= k) {
// 移除k个数之前的元素
map.remove(getBucketID(nums[i-k], t + 1 ));
}
}
return false;
}
private int getBucketID(int num,int bucketSize) {
if (num >= 0) {
return num / bucketSize;
}
return num / bucketSize - 1;
}