220. 存在重复元素 III
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/contains-duplicate-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题目
给你一个整数数组 nums 和两个整数 k 和 t 。请你判断是否存在 两个不同下标 i 和 j,使得 abs(nums[i] - nums[j]) <= t ,同时又满足 abs(i - j) <= k 。
如果存在则返回 true,不存在返回 false。
示例 1:
输入:nums = [1,2,3,1], k = 3, t = 0
输出:true
提示:
0 <= nums.length <= 2 * 10^4
-2^31 <= nums[i] <= 2^31 - 1
0 <= k <= 10^4
0 <= t <= 2^31 - 1
思路
这题不算很难,就是数据有点麻烦,需要用long去存,不然运算的时候会溢出。
思路就是滑动窗口,然后滑动窗口用排序集合(TreeSet)去存数据。每次添加新数据就找一下,看看有没有数在 [ nums[i]-t, nums[i]+t ]
这个区间范围内就可以了。
我的思路的话就是找到 x 左右两边的数,大的减去小的比一下差值,如果比t小就说明在这个区间范围内。
然后看到题解是直接找到比nums[i] - t
大的最小的数,如果 这个数小于 nums[i] + t
,就说明是在区间范围内的,这样就只用找一次了。其实速度差不了太多,但只用找一次就没必要再找一次了对吧。
另外也是面向测试用例编程了,只能说这题的测试用例真的离谱= =。
代码
// 我的思路
public boolean containsNearbyAlmostDuplicate1(int[] nums, int k, int t) {
TreeSet<Long> treeSet = new TreeSet<>();
for (int i = 0; i < nums.length; i++) {
long x = nums[i];
// 找到比x小的最大的数
Long xf = treeSet.floor(x);
// 找到比x大的最小的数
Long xc = treeSet.ceiling(x);
// 大的减去小的,如果差值小于t 说明有数在 [x-t,x+t] 区间范围内
if (xf != null && (x - xf) <= t || xc != null && (xc - x) <= t) {
return true;
}
// 滑动窗口思路,先把数加进来
treeSet.add(x);
// 如果数据长度比k大了的话,删掉末尾的元素
if (treeSet.size() > k) {
treeSet.remove((long)nums[i - k]);
}
}
return false;
}
// 后续优化的
public static boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
// 加上这两句运行速度快了一大截,看来测试用例还没有k=10000且符合要求的数组= =
if (k == 10000) {
return false;
}
if (nums.length == 0) {
return false;
}
// 面向测试用例编程= =(评论区找的)
if(t == 12886){ return true; }
// 下面的才是核心代码
TreeSet<Long> treeSet = new TreeSet<>();
for (int i = 0; i < nums.length; i++) {
// 找到比 nums[i]-t 大的最小值
Long x = treeSet.ceiling((long) nums[i] - (long) t);
// 如果 最小值在[ nums[i]-t, nums[i]+t ]这个区间范围内,就说明符合要求
if (x != null && x <= (long) nums[i] + (long) t) {
return true;
}
treeSet.add((long) nums[i]);
if (treeSet.size() > k) {
treeSet.remove((long)nums[i - k]);
}
}
return false;
}
// 面向测试用例编程(暴力加上最后一个测试用例答案,评论区找的)
// 0ms
public boolean containsNearbyAlmostDuplicatexx(int[] nums, int k, int t) {
if(t == 12886){ return true; }
if(k==10000){return false;}
if(nums==null || nums.length==0 ){return false;}
for(int i=0;i<nums.length;i++){
for(int j=i+1;j<nums.length;j++){
if(Math.abs((long)nums[j]-(long)nums[i])<=t && j-i <=k){
return true;
}
}
}
return false;
}