题解地址:https://leetcode-cn.com/problems/contains-duplicate-iii/solution/hua-dong-chuang-kou-er-fen-sou-suo-shu-zhao-shang-/
方法一:暴力解法
枚举所有长度小于等于 k + 1
的“下标对()
”,只要发现 nums[i] - nums[j]
的绝对值小于 t
,就返回 true
。
Java 代码:
public class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
int len = nums.length;
long a;
long b;
for (int i = 0; i < len; i++) {
for (int j = i + 1; j < len && j <= i + k; j++) {
a = nums[i];
b = nums[j];
if (Math.abs(a - b) <= t) {
return true;
}
}
}
return false;
}
}
复杂度分析:
- 时间复杂度: ,这里数组的长度为 ,枚举可能的数对 。
- 空间复杂度: 。
方法二:滑动窗口(以空间换时间)
题目意思翻译一下:在数组 nums[i]
中,在任意区间 [i, i + k]
里是否存在两个数的绝对值小于等于 t
,即
,
等价于 并且 ,
即 并且 。
Java 代码:
import java.util.TreeSet;
public class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
// 滑动窗口结合查找表,此时滑动窗口即为查找表本身(控制查找表的大小即可控制窗口大小)
TreeSet<Long> set = new TreeSet<>();
for (int i = 0; i < nums.length; i++) {
// 边添加边查找
// 查找表中是否有大于等于 nums[i] - t 且小于等于 nums[i] + t 的值
Long ceiling = set.ceiling((long) nums[i] - (long) t);
if (ceiling != null && ceiling <= ((long) nums[i] + (long) t)) {
return true;
}
// 添加后,控制查找表(窗口)大小,移除窗口最左边元素
set.add((long) nums[i]);
if (set.size() == k + 1) {
set.remove((long) nums[i - k]);
}
}
return false;
}
}
另一种写法:在一开始就把多余的元素删除。
Java 代码:
import java.util.TreeSet;
public class Solution11 {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
int len = nums.length;
// 特判
if (len == 0 || k <= 0 || t < 0) {
return false;
}
TreeSet<Long> set = new TreeSet<>();
for (int i = 0; i < len; i++) {
if (i > k) {
set.remove((long) nums[i - k - 1]);
}
Long ceiling = set.ceiling((long) nums[i] - (long) t);
if (ceiling != null && ceiling <= (long) nums[i] + (long) t) {
return true;
}
set.add((long) nums[i]);
}
return false;
}
}
复杂度分析:
- 时间复杂度: ,遍历数组使用 ,在遍历的同时向二叉搜索树中插入元素和移除元素的时间复杂度是 。
- 空间复杂度: 。