查找表类算法
查找表类算法 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台
两个数组的交集
解法1
- new两个hashset,第一个hashset存放第一个数组
- 第二个数组存放进第二个hashset,放入之前判断是否在第一个hashset中存在(hashset不可重复)
- 将第二个hashset放入数组返回
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> set1 = new HashSet<>();
Set<Integer> set2 = new HashSet<>();
for (Integer number : nums1) {
set1.add(number);
}
for (Integer number : nums2) {
if (set1.contains(number)) {
set2.add(number);
}
}
int[] result = new int[set2.size()];
int count = 0;
for (Integer number : set2) {
result[count] = number;
count++;
}
return result;
}
}
快乐数
解法1
暴力循环
class Solution {
int count = 0;
public boolean isHappy(int n) {
int result = 0;
for (int i = 0; i < 30; i++) {
while (n != 0) {
int num = n % 10;
result += num * num;
n = n / 10;
}
if (result == 1) {
return true;
}
n = result;
result = 0;
count++;
}
return false;
}
}
解法2(思路)
解法1的优化,把每次循环出的结果放到一个hashset中,如果有重复就可以提前return,出现重复就形成循环了,不会快乐了
例子的问题,居然没有暴力循环快,这是没想到的
class Solution {
public boolean isHappy(int n) {
HashSet<Integer> set = new HashSet<Integer>();
while(n != 1){
set.add(n);// 把每次得到 新数字插存入set中
int tmp = n, sum = 0;// sum为新数字
// 计算新数字
while(tmp != 0){
sum += (tmp % 10) * (tmp % 10);
tmp /= 10;
}
if (set.contains(sum)) return false; // 新数字与原来的数字相等 会陷入死循环,即 不为快乐数字
n = sum;
}
return true;
}
}
存在重复元素
解法1
- 使用HashSet存放遍历过的元素
- 如果碰到元素已经放入HashSet中,返回true,否则返回false
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
if (set.contains(nums[i])) {
return true;
}
set.add(nums[i]);
}
return false;
}
}
解法2
解法1的基础上优化
- 不使用contains方法,而用add方法返回值是否成功来进行判断
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
if (!set.add(nums[i])) {
return true;
}
}
return false;
}
}
两个数组的交集Ⅱ
解法1
暴力循环
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
int index = 0;
for (int i = 0; i < nums1.length; i++) {
for (int j = 0; j < nums2.length; j++){
if (nums1[i] == nums2[j]) {
nums1[index] = nums1[i];
nums2[j] = -1;
index++;
break;
}
}
}
int[] result = new int[index];
for (int i = 0; i < index; i++) {
result[i] = nums1[i];
}
return result;
}
}
解法2
- 新建一个数组
- 遍历list1,对于list1中的每个元素,都在新数组中对应下标自增1
- 新建一个result数组用于存放结果
- 遍历list2,对于list2中每个元素,对应新数组中的下标不为0的元素存放入result数组,并把新数组中元素自减1
- 用Arrays的copyOfRange方法返回结果效率较高
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
int[] account = new int[1001];
for (int i = 0; i < nums1.length; i++) {
account[nums1[i]]++;
}
int[] result = new int[Math.min(nums1.length, nums2.length)];
int index = 0;
for (int i = 0; i < nums2.length; i++) {
int val = nums2[i];
if(account[val] > 0) {
account[val]--;
result[index] = val;
index++;
}
}
return Arrays.copyOfRange(result, 0, index);
}
}
有效的字母异位词
解法1
- 使用HashMap,将第一个字符串对应的char放入HashMap,(k, v)=(元素,出现次数)
- 遍历第二个字符串对应的char数组,如果在map中存在就自减1
- 如果在map中不存在,或者存在的value为0,返回false
- 遍历结束返回true
class Solution {
public boolean isAnagram(String s, String t) {
if (s.length() != t.length()) {
return false;
}
Map<Character, Integer> map = new HashMap<>();
char[] c1 = s.toCharArray();
char[] c2 = t.toCharArray();
for (int i = 0; i < c1.length; i++) {
map.put(c1[i], map.getOrDefault(c1[i], 0) + 1);
}
for (int i = 0; i < c2.length; i++) {
if (map.get(c2[i]) == null || map.get(c2[i]) == 0) {
return false;
}
map.put(c2[i], map.get(c2[i]) - 1);
}
return true;
}
}
解法2
- 转char数组
- 排序
- 返回equals判断Stirng.valueOf是否相等
class Solution {
public boolean isAnagram(String s, String t) {
char[] c1 = s.toCharArray();
char[] c2 = t.toCharArray();
Arrays.sort(c1);
Arrays.sort(c2);
return String.valueOf(c1).equals(String.valueOf(c2));
}
}
同构字符串
解法1
- 用两个map存放两个字符串的互相映射
- 遍历字符串
- 如果遍历到某个元素存在映射但是和当前另一个元素不匹配则返回false
- 遍历结束则返回true
class Solution {
public boolean isIsomorphic(String s, String t) {
Map<Character, Character> map = new HashMap<>();
Map<Character, Character> map2 = new HashMap<>();
char[] ss = s.toCharArray();
char[] tt = t.toCharArray();
for (int i = 0; i < ss.length; i++) {
if (map.containsKey(ss[i])) {
if (map.get(ss[i]) != tt[i]) {
return false;
}
}
if (map2.containsKey(tt[i])) {
if (map2.get(tt[i]) != ss[i]) {
return false;
}
}
map.put(ss[i], tt[i]);
map2.put(tt[i], ss[i]);
}
return true;
}
}
解法2
- 用两个数组来做map进行优化
class Solution {
public boolean isIsomorphic(String s, String t) {
char[] char_s = s.toCharArray();
char[] char_t = t.toCharArray();
HashMap<Character, Character> map = new HashMap<>();
for (int i = 0; i < char_s.length; i++) {
if (map.containsKey(char_s[i])) {
if (map.get(char_s[i]) != char_t[i]) {
return false;
}
} else if (map.containsValue(char_t[i])) {
return false;
} else {
map.put(char_s[i], char_t[i]);
}
}
return true;
}
}
根据字符出现频率排序
解法1
- 桶排序
大佬的解法,注释很清楚
class Solution {
public String frequencySort(String s) {
if (s.isEmpty() || s.length() == 1) {
return s;
}
// 构造 HashMap。Key:s 中的每个元素;Value:对应元素出现的次数(即频率)
Map<Character, Integer> store = new HashMap<>();
for (char c : s.toCharArray()) {
// 填充 HashMap。如果当前 Key c 不存在,getOrDefault() 方法返回默认值 0;
// 否则返回当前 Key c 对应的 Value。
// 不管哪种情况最后都在 0 或者 Value 的基础上 +1。
store.put(c, store.getOrDefault(c, 0) + 1);
}
// 构造一个桶的集合(即一系列桶),桶的个数为 s 的长度 +1,因为 buckets[0] 没有意义
// 目的是将出现频率为 i 的字符放到第 i 个桶里(即 buckets[i])
List<Character>[] buckets = new List[s.length() + 1];
for (char key : store.keySet()) {
// 某个字符在 HashMap 中的 Value 是几就会被放到第几个桶里
int value = store.get(key);
if (buckets[value] == null) {
// 如果某个桶还未放入过字符(即未初始化),则初始化其为一个数组
buckets[value] = new ArrayList<Character>();
}
buckets[value].add(key); // 然后将字符放到桶中
}
StringBuilder res = new StringBuilder();
for (int i = buckets.length - 1; i > 0; --i) {
// 遍历每个桶
if (buckets[i] != null) {
// 如果桶里有字符
for (char j : buckets[i]) {
// 遍历桶里的每个字符
for (int k = i; k > 0; --k) {
// 字符出现了几次就向 res 中添加几次该字符
res.append(j);
}
}
}
}
return res.toString();
}
}
实现
class Solution {
public String frequencySort(String s) {
if (s.isEmpty() || s.length() == 1) {
return s;
}
Map<Character, Integer> map = new HashMap<>();
List<Character>[] buckets = new List[s.length() + 1];
char[] ccc = s.toCharArray();
StringBuilder result = new StringBuilder();
for (char c : ccc) {
map.put(c, map.getOrDefault(c, 0) + 1);
}
for (char key : map.keySet()) {
int value = map.get(key);
if (buckets[value] == null) {
buckets[value] = new ArrayList<>();
}
buckets[value].add(key);
}
for (int i = buckets.length - 1; i > 0; i--) {
if (buckets[i] == null) {
continue;
}
for (char c : buckets[i]) {
for (int j = 0; j < i; j++) {
result.append(c);
}
}
}
return result.toString();
}
}
两数之和
解法1
暴力循环
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] result = new int[2];
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if(nums[i] + nums[j] == target) {
result[0] = i;
result[1] = j;
return result;
}
}
}
return result;
}
}
解法2
- 使用HashMap遍历一遍数组(map的key为元素值,value为元素下标)
- 每一次遍历都求出当前元素和target的差,如果该值在map中存在,则直接返回这两个值
- 否则将当前元素加入到map中
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] result = new int[2];
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int number = target - nums[i];
if (map.containsKey(number)) {
result[0] = i;
result[1] = map.get(number);
return result;
}
map.put(nums[i], i);
}
return result;
}
}
解法3
在解法2的基础上优化一丢丢
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (map.containsKey(target - nums[i])) {
return new int[]{i, map.get(target - nums[i])};
}
map.put(nums[i], i);
}
return new int[0];
}
}
三数之和
解法1
英雄哪里出来大佬的视频解法的Java实现
一层枚举加双指针
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
int n = nums.length;
int i, j, k;
for (i = 0; i < n - 2; i++) {
if (i != 0 && nums[i] == nums[i - 1]) {
continue;
}
j = i + 1;
k = n - 1;
while (j < k) {
if (nums[i] + nums[j] + nums[k] > 0) {
k--;
} else if (nums[i] + nums[j] + nums[k] < 0) {
j++;
} else {
List<Integer> re = new ArrayList<>();
re.add(nums[i]);
re.add(nums[j]);
re.add(nums[k]);
result.add(re);
j++;
k--;
while (j < k && nums[j] == nums[j - 1]) {
j++;
}
while (j < k && nums[k] == nums[k + 1]) {
k--;
}
}
}
}
return result;
}
}
解法2
解法1优化,还是大佬的思路,太强了
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
int n = nums.length;
if (n < 3 || nums[0] > 0 || nums[n - 1] < 0) {
return result;
}
if (nums[0] == 0 && nums[n - 1] == 0) {
List<Integer> temp = new ArrayList<>();
temp.add(0);
temp.add(0);
temp.add(0);
result.add(temp);
return result;
}
for (int i = 0; i < n - 2; i++) {
if (i != 0 && nums[i] == nums[i - 1]) {
continue;
}
if (nums[i] > 0) {
break;
}
int j = i + 1;
int k = n - 1;
while (j < k) {
int sum = nums[i] + nums[j] + nums[k];
if (sum > 0) {
k--;
} else if (sum < 0) {
j++;
} else {
List<Integer> temp = new ArrayList<>();
temp.add(nums[i]);
temp.add(nums[j]);
temp.add(nums[k]);
result.add(temp);
j++;
k--;
while (j < k && nums[j] == nums[j - 1]) {
j++;
}
while (j < k && nums[k] == nums[k + 1]) {
k--;
}
}
}
}
return result;
}
}
四数之和
解法1
英雄哪里出来大佬的视频解法的Java实现
两层枚举加双指针
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
int n = nums.length;
int i, j, k, l;
if (n < 4) {
return result;
}
Long sum4 = (long)(nums[0]) + (long)nums[1] + (long)nums[2] + (long)nums[3];
for (i = 0; i < n; i++) {
if (sum4 > target) {
break;
}
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
for (j = i + 1; j < n; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
l = j + 1;
k = n - 1;
while (l < k) {
Long temp = (long)(nums[i]) + (long)nums[j] + (long)nums[l] + (long)nums[k];
if (temp > target) {
k--;
} else if (temp < target) {
l++;
} else {
List<Integer> re = new ArrayList<>();
re.add(nums[i]);
re.add(nums[j]);
re.add(nums[l]);
re.add(nums[k]);
result.add(re);
l++;
k--;
while (l < k && nums[l] == nums[l - 1]) {
l++;
}
while (l < k && nums[k] == nums[k + 1]) {
k--;
}
}
}
}
}
return result;
}
}
解法2
跟着大佬的思路继续优化,思路看视频
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
int n = nums.length;
int i, j, k, l;
if (n < 4) {
return result;
}
Long sum4 = (long)(nums[0]) + (long)nums[1] + (long)nums[2] + (long)nums[3];
Long max3 = (long)(nums[n - 1]) + (long)nums[n - 2] + (long)nums[n - 3];
Long max2 = (long)nums[n - 1] + nums[n - 2];
for (i = 0; i < n - 3; i++) {
if (sum4 > target) {
break;
}
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
if (max3 + nums[i] < target) {
continue;
}
Long sum3 = (long)nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3];
for (j = i + 1; j < n - 2; j++) {
if (sum3 > target) {
break;
}
if (j + 3 < n) {
sum3 = sum3 - nums[j] + nums[j + 3];
}
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
if (max2 + nums[i] + nums[j] < target) {
continue;
}
l = j + 1;
k = n - 1;
while (l < k) {
Long temp = (long)(nums[i]) + (long)nums[j] + (long)nums[l] + (long)nums[k];
if (temp > target) {
k--;
} else if (temp < target) {
l++;
} else {
List<Integer> re = new ArrayList<>();
re.add(nums[i]);
re.add(nums[j]);
re.add(nums[l]);
re.add(nums[k]);
result.add(re);
l++;
k--;
while (l < k && nums[l] == nums[l - 1]) {
l++;
}
while (l < k && nums[k] == nums[k + 1]) {
k--;
}
}
}
}
}
return result;
}
}
四数相加Ⅱ
解法1
- 四个数组分为两组
- 将AB的和及出现的次数放入到HashMap中
- 计算CD的和*(-1)如果在HashMap中出现则计数结果自增对应的value值
- 返回计数结果
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int count = 0;
Map<Integer, Integer> map = new HashMap<>();
int sumAB;
int sumCD;
for (int i = 0; i < nums1.length; i++) {
for (int j = 0; j < nums2.length; j++) {
sumAB = nums1[i] + nums2[j];
if (map.containsKey(sumAB)) {
map.put(sumAB, map.get(sumAB) + 1);
continue;
}
map.put(sumAB, 1);
}
}
for (int i = 0; i < nums3.length; i++) {
for (int j = 0; j < nums4.length; j++) {
sumCD = (nums3[i] + nums4[j]) * (-1);
if (map.containsKey(sumCD)) {
count += map.get(sumCD);
}
}
}
return count;
}
}
字母异位词分组
解法1
- 将每个字符串排序后放入一个新的字符串数组,与原数组对应
- 遍历原数组
- 如果对应的排序后的数组对应值存在在map中,则将原数组的元素添加到map的value(List)里
- 如果不存在,则将原数组元素作为key,新数组元素作为value(放入list),put进map
- 遍历map取出所有value放入result(List)返回
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
String[] newstr = new String[strs.length];
List<List<String>> result = new ArrayList<>();
Map<String, List<String>> map = new HashMap<>();
for (int i = 0; i < strs.length; i++) {
char[] ss = strs[i].toCharArray();
Arrays.sort(ss);
newstr[i] = String.valueOf(ss);
}
for (int i = 0; i < strs.length; i++) {
if (map.containsKey(newstr[i])) {
map.get(newstr[i]).add(strs[i]);
continue;
}
List<String> list = new ArrayList<>();
list.add(strs[i]);
map.put(newstr[i], list);
}
// Iterator iterator = map.keySet().iterator();
for (Map.Entry<String, List<String>> entry : map.entrySet()) {
result.add(entry.getValue());
}
return result;
}
}
解法2
- 遍历字符串数组
- 将元素排序,并在map中get元素的value
- 如果value为null,则将字符串和对应的ArrayList(空的)放入map中,并将ArrayList放入result中
- 向ArrayList中添加元素
- 返回result
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
List<List<String>> result = new ArrayList<>();
Map<String, ArrayList<String>> map = new HashMap<>();
char[] ccc;
String sss;
ArrayList<String> temp = null;
for (String str : strs) {
ccc = str.toCharArray();
Arrays.sort(ccc);
sss = String.valueOf(ccc);
temp = map.get(sss);
if (temp == null) {
temp = new ArrayList<>();
map.put(sss, temp);
result.add(temp);
}
temp.add(str);
}
return result;
}
}
回旋镖的数量
解法1
- 遍历所有节点
- 将当前节点和其他节点距离作为key,出现距离的次数作为value存入map
- 遍历map,result自加每个节点的value*(value-1)
- 返回result
class Solution {
public int numberOfBoomerangs(int[][] points) {
int result = 0;
Map<Integer, Integer> map = null;
for (int[] m : points) {
map = new HashMap<>();
for (int[] n : points) {
int len = (m[0] - n[0]) * (m[0] - n[0]) + (m[1] - n[1]) * (m[1] - n[1]);
map.put(len, map.getOrDefault(len, 0) + 1);
}
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
result += entry.getValue() * (entry.getValue() - 1);
}
}
return result;
}
}
直线上最多的点数
解法1
- 遍历数组所有点
- 针对每个点再次遍历数组,计算出当前点和所有点的斜率,将斜率(key)和出现次数(value)放入map
- 遍历map,将value和max中的最大值放入max,继续下一次遍历
- 返回max
class Solution {
public int maxPoints(int[][] points) {
int max = 1;
Map<Double, Integer> map = null;
for (int[] point : points) {
map = new HashMap<>();
for (int[] p : points) {
if (p == point) {
continue;
}
double k = Integer.MAX_VALUE;
if (point[0] - p[0] != 0) {
k = ((double)p[1] - point[1]) / (p[0] - point[0]);
}
map.put(k, map.getOrDefault(k, 0) + 1);
}
for (int value : map.values()) {
max = Math.max(max, value + 1);
}
}
return max;
}
}
存在重复元素Ⅱ
解法1
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (!map.containsKey(nums[i])) {
map.put(nums[i], i);
continue;
}
if (i - map.get(nums[i]) <= k) {
return true;
}
map.put(nums[i], i);
}
return false;
}
}
存在重复元素Ⅲ
【宫水三叶】一题双解:「滑动窗口 & 二分」&「桶排序」解法 - 存在重复元素 III - 力扣(LeetCode)
解法1
桶排序
class Solution {
long size;
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
int n = nums.length;
Map<Long, Long> map = new HashMap<>();
size = t + 1L;
for (int i = 0; i < n; i++) {
long u = nums[i] * 1L;
long idx = getIdx(u);
// 目标桶已存在(桶不为空),说明前面已有 [u - t, u + t] 范围的数字
if (map.containsKey(idx)) return true;
// 检查相邻的桶
long l = idx - 1, r = idx + 1;
if (map.containsKey(l) && u - map.get(l) <= t) return true;
if (map.containsKey(r) && map.get(r) - u <= t) return true;
// 建立目标桶
map.put(idx, u);
// 移除下标范围不在 [max(0, i - k), i) 内的桶
if (i >= k) map.remove(getIdx(nums[i - k] * 1L));
}
return false;
}
long getIdx(long u) {
return u >= 0 ? u / size : ((u + 1) / size) - 1;
}
}
解法2
滑动窗口,二分
class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
int n = nums.length;
TreeSet<Long> ts = new TreeSet<>();
for (int i = 0; i < n; i++) {
Long u = nums[i] * 1L;
// 从 ts 中找到小于等于 u 的最大值(小于等于 u 的最接近 u 的数)
Long l = ts.floor(u);
// 从 ts 中找到大于等于 u 的最小值(大于等于 u 的最接近 u 的数)
Long r = ts.ceiling(u);
if(l != null && u - l <= t) return true;
if(r != null && r - u <= t) return true;
// 将当前数加到 ts 中,并移除下标范围不在 [max(0, i - k), i) 的数(维持滑动窗口大小为 k)
ts.add(u);
if (i >= k) ts.remove(nums[i - k] * 1L);
}
return false;
}
}
解法3
评论区找到的大佬用二叉搜索树+TreeSet+桶排序解决的
/**
* @author miemiehoho
* @date 2021/11/10 11:14
*/
public // 利用二叉搜索树维护长度为k的滑动窗口内的数
class Solution {
class TreeNode {
long val;
TreeNode left;
TreeNode right;
TreeNode() {
}
TreeNode(long val) {
this.val = val;
}
TreeNode(long val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
TreeNode root;
int size = 0;
// 查找的时间复杂度为O(h)
public boolean searchBST(TreeNode root, long minVal, long maxVal) {
if (root == null) {
return false;
}
if (root.val >= minVal && root.val <= maxVal) {
return true;
}
if (root.val > maxVal) {
return searchBST(root.left, minVal, maxVal);
}
return searchBST(root.right, minVal, maxVal);
}
public void insert(TreeNode root, long val) {
this.root = insertIntoBST(root, val);
}
// 插入的时间复杂度为O(N),其中 N 为树中节点的数目。最坏情况下,我们需要将值插入到树的最深的叶子结点上,而叶子节点最深为 O(N)
private TreeNode insertIntoBST(TreeNode root, long val) {
if (root == null) {
size++;
return new TreeNode(val);
}
if (root.val > val) {
root.left = insertIntoBST(root.left, val);
} else {
root.right = insertIntoBST(root.right, val);
}
return root;
}
public void delete(TreeNode root, long key) {
this.root = deleteNode(root, key);
}
// 删除操作的时间复杂度为O(h),h为树的高度
private TreeNode deleteNode(TreeNode root, long key) {
if (root == null) {
return null;
}
if (root.val > key) {
root.left = deleteNode(root.left, key);
}
if (root.val < key) {
root.right = deleteNode(root.right, key);
}
if (root.val == key) {
if (root.left == null) {
return root.right;
}
if (root.right == null) {
return root.left;
}
TreeNode minNode = minNode(root.right);
root.val = minNode.val;
size--;
root.right = deleteNode(root.right, root.val);
}
return root;
}
private TreeNode minNode(TreeNode root) {
if (root == null) {
return root;
}
while (root.left != null) {
root = root.left;
}
return root;
}
// // 删除操作的时间复杂度为 O(h),h 为树的高度
// public TreeNode deleteNode(TreeNode root, int key) {
// if (root == null) {
// return root;
// }
// if (root.val > key) {
// root.left = deleteNode(root.left, key);
// }
// if (root.val < key) {
// root.right = deleteNode(root.right, key);
// }
// if (root.val == key) {
// root = newTree(root);
// }
// return root;
// }
//
// private TreeNode newTree(TreeNode root) {
// if (root.left == null) {
// return root.right;
// }
// if (root.right == null) {
// return root.left;
// }
// // 找到右子树最小值
// TreeNode cur = root.right;
// while (cur.left != null) {
// cur = cur.left;
// }
// cur.left = root.left;
// return root.right;
// }
// 利用 BTS维护大小为k的滑动窗口
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
if (nums.length <= 1) {
return false;
}
for (int i = 0; i < nums.length; i++) {
long minVal = (long)nums[i] - t;
long maxVal = (long)nums[i] + t;
if (searchBST(root, minVal, maxVal)) {
return true;
}
insert(root, nums[i]);
if (size > k) {
delete(root, nums[i - k]);
}
}
return false;
}
}