一、题目
1、审题
2、分析
判断数组中是否存在两个元素之差在 t 之内,且此两个元素下标之差在 k 之内。
二、解答
1、思路:
方法一、
桶排序
①、采用 Map ,key 记录桶的序号,value 记录元素的值。每个桶的元素个数为 t + 1, eg t=3,则桶大小为 4, 元素 0、1、2、3 在一个桶,桶元素最大差值为 3 - 0 = 3 <= t 。
②、由于存在 (t + 1, -t -1) 都存在于桶序号为 0 的同一个桶,为了消除这个错误,将元素化为 Long,且值均大于 0。做法是 key 用 nums[i] - Integer.MIN_VALUE 表示。
③、若遍历的连续的 k 个元素中出现在同一个桶情况,则返回 true,若有连续桶,则比较这两个元素值。
④、当桶数大于 k 了,则去除最早添加的一个桶,添加新的遍历的元素的 entry。
1 public boolean containsNearbyAlmostDuplicate2(int[] nums, int k, int t) { 2 3 if(k < 1 || t < 0) 4 return false; 5 6 HashMap<Long, Long> map = new HashMap<>(); 7 for (int i = 0; i < nums.length; i++) { 8 // Integer 范围是 [-2147483648, 2147483647] 9 // nums[i] - Integer.MIN_VALUE 使得所有数值均 >= 0, 否则 (t+1, -t-1) 均在 0 这个桶内 10 long remappendNum = (long) nums[i] - Integer.MIN_VALUE; 11 long bucket = remappendNum / ((long)t + 1); 12 if(map.containsKey(bucket) 13 || (map.containsKey(bucket - 1) && remappendNum - map.get(bucket - 1) <= t) 14 || (map.containsKey(bucket + 1) && map.get(bucket + 1) - remappendNum <= t)) 15 return true; 16 17 if(map.entrySet().size() >= k) { 18 long lastBucket = ((long) nums[i - k] - Integer.MIN_VALUE) / ((long)t + 1); 19 map.remove(lastBucket); 20 } 21 map.put(bucket, remappendNum); 22 } 23 return false; 24 }
方法二、
采用 TreeSet
注意将 Integer 转为 Long 型进行比较,避免溢出情况。
1 // TreeSet 继承自 NavigableSet,NavigableSet 提供导航方法: 2 /* 3 * 1、 lower(e): 返回 小于 给定值的元素 4 * 2、floor(e): 小于等于 5 * 3、ceiling(e): 大于等于 6 * 4、higher(e): 大于 7 */ 8 public boolean containsNearbyAlmostDuplicate3(int[] nums, int k, int t) { 9 10 if(k < 1 || t < 0) 11 return false; 12 13 TreeSet<Long> values = new TreeSet<>(); 14 for (int i = 0; i < nums.length; i++) { 15 long num = nums[i]; // 转为 Long 型,避免了整形溢出情况。 16 Long floor = values.floor(num + t); // 小于等于 17 Long ceil = values.ceiling(num - t); // 大于等于 18 if((floor != null && floor >= num) 19 || (ceil != null && ceil <= num)) 20 return true; 21 22 values.add(num); 23 if(i >= k) 24 values.remove((long)(nums[i - k])); 25 } 26 return false; 27 }