[LeetCode]Contains Duplicate III
原创
©著作权归作者所有:来自51CTO博客作者byamao1的原创作品,请联系作者获取转载授权,否则将追究法律责任
Question
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.
本题难度Medium。有2种算法分别是: 遍历法(超时)和二叉搜索树
注意
t可以等于0
1、遍历法
复杂度
时间 O(N*k) 空间 O(1)
思路
对每个待考察数x,搜索其前面的k个数看是否有满足条件:abs(x-nums[j])<=t
附
该方法是 Time limit exceeded.
注意
第11行不要写为:if(Math.abs(num-nums[i-j])<=t)
,如果遇到
Input:
[-1,2147483647]
1
2147483647
就会出错,原因是差值超出整型范围。
代码
public class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
//require
if(nums==null||nums.length<2||k<1)
return false;
//invariant
for(int i=0;i<nums.length;i++){
int num = nums[i];
for(int j=1;j<=k;j++){
if(i-j<0)break;
if(Math.abs((long)num-nums[i-j])<=t)
return true;
}
}
//ensure
return false;
}
}
2、二叉搜索树
复杂度
时间 O(Nlogk) 空间 O(k)
思路
要求判断之前是否存在差值小于t的数字,我们需要知道在当前数字x两边的数字,即最大的小于x的数字和最小的大于x的数字。二叉搜索树有也有这样的性质,它的左子树的最右节点是最大的较小值,右子树的最左节点是最小的较大值。这里我们用TreeSet这个类,它实现了红黑树,并有集合的性质,非常适合这题。我们同样也是维护一个大小为k的TreeSet,多余k个元素时把最早加入的给删除。用ceiling()和floor()可以找到最小的较大值和最大的较小值。
注意
第6行不要写成Set<Integer> set = new TreeSet<>();
,方法ceiling和floor并不是超类Set的方法。
代码
public class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
//require
if(nums==null||nums.length<2||k<1)
return false;
TreeSet<Integer> set = new TreeSet<>();
//invariant
for(int i=0;i<nums.length;i++){
int x = nums[i];
//return the min in elements which >= x
if(set.ceiling(x)!=null&&set.ceiling(x)<=x+t)return true;
//return the max in elements which <= x
if(set.floor(x)!=null&&x<=set.floor(x)+t)return true;
set.add(x);
if(set.size()>k)set.remove(nums[i-k]);
}
//ensure
return false;
}
}
参考
[Leetcode] Contains Duplicate 包含重复