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;

    }

}

原文地址:https://www.cnblogs.com/codeskiller/p/6359733.html