题目:

给你一个整数数组 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
示例 2:

输入:nums = [1,0,1,1], k = 1, t = 2
输出:true
示例 3:

输入:nums = [1,5,9,1,5,9], k = 2, t = 3
输出:false

提示:

  • 0 <= nums.length <= 2 * 104
  • -231 <= nums[i] <= 231 - 1=2147483647
  • 0 <= k <= 104
  • 0 <= t <= 231 - 1

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/contains-duplicate-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

题解参考@【liweiwei1419】

滑动窗口&红黑树(TreeSet):

题目中的两个要求: 两个不同下标 i 和 j,使得 abs(nums[i] - nums[j]) <= t,同时又满足abs(i - j) <= k。 

1.对于两个位置的下标的范围,可以维护一个长度为 k + 1的滑动窗口(解释:[1,3,5,3,4,6] k =3,滑动窗口的长度可以为4,因为在四个连续的数的下标差一定会小于等于3)。但是滑动窗口中的元素可能为k个,也可能为k+1个,如果先插入新元素则是k+1个,如果是先删除最左端的元素,则是k个。

2.对于两个位置所对应的数字差范围:abs(nums[i] - nums[j]) <= t,可以转换为:-t <= nums[i] - nums[j] <= t,把nums[i]看做新遍历到的元素,nums[j]看做是在滑动窗口里面的元素,将上述不等式可以转换为:

  • 条件1:nums[j] >= nums[i] - t;
  • 条件2:nums[j] <= nums[i] + t;

条件2的nums[i] + t的值固定,为了让条件2有更多的值成立,条件1找到得到nums[j]需要尽可能的小才行,于是就等价于找大于等于nums[i] - t的最小值,等价于找到nums[i] - t的最小上界。java中的ceiling(key)函数提供了这样的功能:返回大于等于key的最小元素,如果不存在,返回空。

为什么使用二分搜索树】解释来自【作者:liweiwei1419】
理由 1:由于维护的是固定长度的一系列数,除了最开始的几个数添加进数据结构以外。

当程序看到下标为 k + 1的元素的时候,就需要移除下标为 00 的元素;
当程序看到下标为 k + 2的元素的时候,就需要移除下标为 11 的元素。
频繁的删除和添加元素,符合条件的数据结构是「查找表」,「查找表」的两种实现分别是「哈希表」和「二分搜索树(红黑树)」。

理由 2:根据上面的分析,我们需要找到 nums[i] - t 的最小上界,「哈希表」是不维护元素顺序性的,而「二分搜索树」恰好维护了顺序性,是当前场景下合适的数据结构。且哈希表无法很好的支持范围查询。

注意:

int的溢出问题:例如nums= [-2147483640, -2147483641],k = 1, t = 100,nums[i] - t = -21474836740就会超过int 的最小值范围,故用long 类型来存储。

java代码:

 1 class Solution {
2 public boolean containsNearbyAlmostDuplicate(int[] nums, int indexDiff, int valueDiff) {
3 TreeSet<Long> set = new TreeSet<>();
4 for(int i = 0; i < nums.length; i++){
5 //查找大于等于nums[i]-t的最小值
6 Long ceiling = set.ceiling((long)nums[i] - (long)valueDiff);
7 if(ceiling != null && ceiling <= ((long)nums[i] + (long)valueDiff)){
8 return true;
9 }
10 set.add((long)nums[i]);
11 //限制滑动窗口的大小
12 if(set.size() == indexDiff + 1){
13 set.remove((long)nums[i - indexDiff]);
14 }
15 }
16 return false;
17 }
18 }

 小知识:

1.java集合中存在以下两种方法:

floor(E e) 方法返回在这个集合中小于或者等于给定元素的最大元素,如果不存在这样的元素,返回null。

ceiling(E e) 方法返回在这个集合中大于或者等于给定元素的最小元素,如果不存在这样的元素,返回null。

2.TreeSet 是一个有序集合,它的作用是提供有序的Set集合。其继承于 AbstractSet 类TreeSet 实现了 NavigableSet 接口,意味着它支持一系列的导航方法。比如查找指定目标最匹配项。

TreeSet 是通过 TreeMap 实现的一个有序的、不可重复的集合,底层维护的是红黑树结构。当TreeSet的泛型对象不是java的基本类型的包装类时,对象需要实现接口Comparable并重写此接口中的compareTo()方法。 TreeSet 实现了 Serializable 接口,所以它支持序列化。

力扣220(java)-存在重复元素 III(困难)的更多相关文章

  1. Java实现 LeetCode 220 存在重复元素 III(三)

    220. 存在重复元素 III 给定一个整数数组,判断数组中是否有两个不同的索引 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最 ...

  2. Leetcode 220.存在重复元素III

    存在重复元素III 给定一个整数数组,判断数组中是否有两个不同的索引 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最大为 ķ. ...

  3. 【每日算法】存在重复元素 III

    题目描述 这是 LeetCode 上的 220. 存在重复元素 III, 难度为 [中等] 给你一个整数数组 nums 和两个整数 k 和 t .请你判断是否存在 两个不同下标 i 和 j,使得 ab ...

  4. [LeetCode] 220. Contains Duplicate III 包含重复元素 III

    Given an array of integers, find out whether there are two distinct indices i and j in the array suc ...

  5. 力扣——remove element(删除元素) python实现

    题目描述: 中文: 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) ...

  6. 力扣题目汇总(重复N次元素,反转字符串,斐波那契数)

    重复 N 次的元素 1.题目描述 在大小为 2N 的数组 A 中有 N+1 个不同的元素,其中有一个元素重复了 N 次. 返回重复了 N 次的那个元素. 示例 1: 输入:[1,2,3,3] 输出:3 ...

  7. [LeetCode]220. 存在重复元素 III

    题目链接:https://leetcode-cn.com/problems/contains-duplicate-iii/ 题目描述: 给定一个整数数组,判断数组中是否有两个不同的索引 i 和 j,使 ...

  8. 220. 存在重复元素 III

    题目: 给定一个整数数组,判断数组中是否有两个不同的索引 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最大为 ķ. 示例 1: ...

  9. 力扣Leetcode 3. 无重复字符的最长子串

    无重复字符的最长子串 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例 示例 1: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串 ...

  10. [Swift]LeetCode220. 存在重复元素 III | Contains Duplicate III

    Given an array of integers, find out whether there are two distinct indices i and j in the array suc ...

随机推荐

  1. docker部署文件

  2. Base MYSQL Database create stored procedures resolve the Delimiter error

    Base MYSQL Database create stored procedures resolve the Delimiter error, It must be created using a ...

  3. 【剑指 Offer II 118. 多余的边】并查集求回路

    class Solution { int[] parent; int[] rank; public void init(int n) { parent = new int[n + 1]; rank = ...

  4. 3DCAT首届行业生态交流会|燧光CTO 戴景文:云渲染 XR大发展的助推器

    2021年12月17日下午,由深圳市瑞云科技有限公司主办,深圳市虚拟现实产业联合会协办的 云XR如何赋能元宇宙--3DCAT实时云渲染首届行业生态合作交流会 圆满落幕.此次活动围绕"云XR如 ...

  5. .NET周刊【3月第2期 2024-03-17】

    国内文章 开源.NET8.0小项目伪微服务框架(分布式.EFCore.Redis.RabbitMQ.Mysql等) https://www.cnblogs.com/aehyok/p/18058032 ...

  6. 自定义Key类型的字典无法序列化的N种解决方案

    当我们使用System.Text.Json.JsonSerializer对一个字典对象进行序列化的时候,默认情况下字典的Key不能是一个自定义的类型,本文介绍几种解决方案. 一.问题重现 二.自定义J ...

  7. 2024-03-23:用go语言,一张桌子上总共有 n 个硬币 栈 。每个栈有 正整数 个带面值的硬币, 每一次操作中,你可以从任意一个栈的 顶部 取出 1 个硬币,从栈中移除它,并放入你的钱包里。

    2024-03-23:用go语言,一张桌子上总共有 n 个硬币 栈 .每个栈有 正整数 个带面值的硬币, 每一次操作中,你可以从任意一个栈的 顶部 取出 1 个硬币,从栈中移除它,并放入你的钱包里. ...

  8. drools中使用全局变量

    一.背景 在我们编写drools的规则文件的时候,有些时候需要用到全局变量,那么这个该怎么实现呢?有哪些注意事项呢? 二.前置知识 1.语法结构 2.全局变量的特点 使用global来定义全局变量,它 ...

  9. 从零开始写 Docker(九)---实现 mydocker ps 查看运行中的容器

    本文为从零开始写 Docker 系列第九篇,实现类似 docker ps 的功能,使得我们能够查询到后台运行中的所有容器. 完整代码见:https://github.com/lixd/mydocker ...

  10. C# 消息发送

    界面 frmMain using System; using System.Collections.Generic; using System.ComponentModel; using System ...