220. Contains Duplicate III
Given an array of integers, find out whether there are two distinct indices i and j in the array such that the absolute difference between nums[i] and nums[j] is at most t and the absolute difference between i and j is at most k.
此题和contains Duplicate的1,2略有不同,在2的基础上添加的一个条件,即定义域为k的范围内的数组,值域为t。
此题开始没有什么思路,看了大神的解体方法后恍然大悟。
1. bucket方法,一般来说,给出了定义域和值域的题目都可以用bucket方法来解决。此题就是这种类型。首先,数组里面因为有负数,所以为了统一整个数组的范围全部为正数,有nums[i]-Integer.MIN_VALUE操作。因为数组里面的数全部是整型,不存在小数点的情况,所以每一个bucket的范围内如果要能装下t的值域范围,bucket的范围就应该是t+1,一会将会举例说明。这里要用到hashmap的数据结构,hashmap的key值为bucket值,value值为nums[i]-Integer.MIN_VALUE。那么接下来就有三种情况要考虑。第一种情况,如果hashmap的key值包括新求出的bucket值,那么肯定符合条件了。第二种情况,如果hashmap的key值包括新求出的bucket-1的值,那么就要看nums[i]-Integer.MIN_VALUE与map.get(bucket-1)的差值是否在t的范围内。第三种情况,如果hashmap的key值包括新求出的bucket+1的值,那么就要看nums[i]-Integer.MIN_VALUE与map.get(bucket+1)的差值是否在t的范围内。
假设数组里面全是正整数,这里不给定义域了,值域为3.注意看bucket=2的情况,bucket-1=1,而8-6=2,也在3的范围里面,所以也符合条件,代码如下:
public class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
Map<Long,Long> map = new HashMap<Long,Long>();
if(k<1||t<0) return false;
for(int i=0;i<nums.length;i++){
long remappedNum = (long)nums[i]-Integer.MIN_VALUE;
long bucket = remappedNum/((long)t+1);
if(map.containsKey(bucket)||map.containsKey(bucket-1)&&(remappedNum-map.get(bucket-1))<=t||map.containsKey(bucket+1)&&(map.get(bucket+1)-remappedNum)<=t) return true;
if(map.size()>=k){
long lastbucket = ((long)nums[i-k]-Integer.MIN_VALUE)/((long)t+1);
map.remove(lastbucket);
}
map.put(bucket,remappedNum);
}
return false;
}
}
第二种方法用二分搜索树来做,注意treeset的两个方法即floor(返回此 set 中小于等于给定元素的最大元素;如果不存在这样的元素,则返回 null
)和ceiling(返回此 set 中大于等于给定元素的最小元素;如果不存在这样的元素,则返回 null
)。代码如下:
public class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
if(nums==null||k<1||t<0) return false;
TreeSet<Long> value =new TreeSet<Long>();
for(int i=0;i<nums.length;i++){
Long floor = value.floor((long)nums[i]+t);
Long ceil = value.ceiling((long)nums[i]-t);
if((floor!=null&&floor>=(long)nums[i])||(ceil!=null&&ceil<=(long)nums[i])){
return true;
}
value.add((long)nums[i]);
if(i>=k){
value.remove((long)nums[i-k]);
}
}
return false;
}
}