LeetCode 220. Contains Duplicate III 题解 -- 转载

本文提供了一种使用TreeSet和Bucket方法解决LeetCode含有重复项III问题的高效算法。通过维护一个长度为k的窗口,利用TreeSet的subSet函数检查是否存在指定范围内的数值,实现O(nlogk)的时间复杂度。此外,还介绍了一种Bucket方法,通过映射数值到桶(bucket),并检查桶内及相邻桶是否有满足条件的数值,达到O(nums.length)的时间复杂度。

https://www.cnblogs.com/Dylan-Java-NYC/p/4924607.html

原题链接在这里:https://leetcode.com/problems/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 difference between nums[i] and nums[j] is at most t and the difference between i and j is at most k.

题解:

借助于TreeSet的subSet函数,看是否有[nums[i]-t, nums[i]+t]范围内的数。

同时维护一个长度为k的窗口,超过了这个长度时就把前面的元素从window中拿出去。

若在window长度范围内,就把nums[i]加进window中。

Note: 

当i>=k, 也就是TreeSet.size()>=k时, 就把这个nums[i-k]从window中拿出去.

这里要先把旧的拿出去才能加新的,因为若是这个要加的新的恰好等于旧的,就会覆盖掉原来的,再拿掉时就会错拿新的。

Time Complexity is O(nlogk). window 的长度为k, TreeSet的contains, insert, delete用时都是O(log k).

Space O(k).

AC Java:

复制代码
 1 public class Solution {
 2     public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
 3         if(nums == null || nums.length < 2 || k < 1 || t<0){
 4             return false;
 5         }
 6         TreeSet<Long> window = new TreeSet<Long>();
 7         for(int i = 0; i<nums.length; i++){
 8             SortedSet<Long> set = window.subSet((long)nums[i]-t, true, (long)nums[i]+t, true);
 9             if(!set.isEmpty()){
10                 return true;
11             }else{
12                 if(i>=k){
13                     window.remove((long)nums[i-k]);
14                 }
15                 window.add((long)nums[i]);
16             }
17         }
18         return false;
19     }
20 }
复制代码

也可采用Bucket. e.g. t=2, 就把(0,1,2)放在一个bucket, (3,4,5)放在下一个bucket等等.

当新的num mapped 到的bucket已经有数, 则return true. 并且检查上下各一个bucket. 上面的例子3-2=1也是小于t的.

这里负数也是允许的, -2/3 = 0, 2/3 = 0. -2 和 2 会map到一个bucket下面. 但2-(-2) = 4已经大于t了. 所以map时num都从Integer.MIN_VALUE开始计数.

另为了避免t=0的情况,求bucketNum时,除以(t+1).

Time Complexity: O(nums.length). Space: O(k).

AC Java:

复制代码
 1 public class Solution {
 2     public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
 3         if(nums == null || nums.length < 2 || k < 1 || t < 0){
 4             return false;
 5         }
 6         
 7         HashMap<Long, Long> hm = new HashMap<Long, Long>();
 8         for(int i = 0; i<nums.length; i++){
 9             long mappedNum  = (long)nums[i] - Integer.MIN_VALUE;
10             long bucketNum = mappedNum/((long)t+1);
11             if(hm.containsKey(bucketNum)
12                 ||(hm.containsKey(bucketNum-1) && mappedNum-hm.get(bucketNum-1)<=t)
13                 ||(hm.containsKey(bucketNum+1) && hm.get(bucketNum+1)-mappedNum<=t)){
14                     return true;
15             }else{
16                 if(i >= k){
17                     long lastBucketNum = ((long)nums[i-k]-Integer.MIN_VALUE)/((long)t+1);
18                     hm.remove(lastBucketNum);
19                 }
20                 hm.put(bucketNum, mappedNum);
21             }
22         }
23         return false;
24     }
25 }
复制代码

类似Contains Duplicate II.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值