Contains Duplicate III LT220
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.
Example 1:
Input: nums = [1,2,3,1], k = 3, t = 0
Output: true
Example 2:
Input: nums = [1,0,1,1], k = 1, t = 2
Output: true
Example 3:
Input: nums = [1,5,9,1,5,9], k = 2, t = 3
Output: false
Idea 1. Similar to Contains Duplicate II LT219, instead of 0 difference, here is at most t difference, normal hashSet cann't effciently tell if there exists elements (nums[i] - t, nums[i]+t) unless loop the whole range, hence TreeSet could be a good tool, to extract the sorted neighbours of nums[i], and see if the difference to its neighbours is at most t.
Time Complexity: O(NlgK)
Space complexity: O(K)
1 import java.util.NavigableSet; 2 class Solution { 3 public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { 4 TreeSet<Integer> window = new TreeSet<>(); 5 6 for(int right = 0; right < nums.length; ++right) { 7 Integer prev = window.floor(nums[right]); 8 Integer next = window.higher(nums[right]); 9 10 if((prev != null && (long)nums[right] - prev <= t) 11 || (next != null && (long)next - nums[right] <= t)) { 12 return true; 13 } 14 window.add(nums[right]); 15 16 if(right >= k) { 17 window.remove(nums[right-k]); 18 } 19 } 20 21 return false; 22 } 23 }
Idea 2. Interesting idea with buckets to map the range[0...t] to a bucket slot, if nums[i] and nums[j] map to the same bucket, it means that their diff is at most, the difference between the sorted tail of buckets[k] and the sorted head of buckets[k+1] could be in range as well, so need to check two neighbour buckets[k-1] and buckets[k+1].
Note. integer overflow, only convert to long if needed, for example during calcuation (+/-), but no need to change Map<Integer, Integer> to Map<Long, Integer>, also t + 1 could be overflow, do (long)t + 1 instead.
Time complexity: O(N)
Space complexity: O(N)
1 class Solution { 2 public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { 3 if(t < 0) { 4 return false; 5 } 6 7 Map<Integer, Integer> buckets = new HashMap<>(); 8 9 for(int right = 0; right < nums.length; ++right) { 10 int bucketKey = (int)( ( (long) nums[right] - Integer.MIN_VALUE ) / ( (long)t+1) ); 11 12 if(buckets.containsKey(bucketKey) 13 || (buckets.containsKey(bucketKey-1) && (long)nums[right] - buckets.get(bucketKey-1) <= t) 14 || (buckets.containsKey(bucketKey+1) && (long)buckets.get(bucketKey+1) - nums[right] <= t)) { 15 return true; 16 } 17 buckets.put(bucketKey, nums[right]); 18 19 if(right >= k) { 20 int key = (int)( ( (long)nums[right-k] - Integer.MIN_VALUE ) / ( (long)t+1) ); 21 buckets.remove(key); 22 } 23 } 24 25 return false; 26 } 27 }