剑指 Offer II 057. 存在重复元素 III
题目要求
leetcode地址
给你一个整数数组 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 * 10^4
- 2^31 <= nums[i] <= 2^31 - 1
- 0 <= k <= 10^4
- 0 <= t <= 2^31 - 1
思路及步骤
步骤如下:
- 首先,定义一个有序的 TreeSet 集合 set,用来存储元素。
- 然后,遍历整数数组 nums。
- 在每次遍历过程中,首先找到 set 中大于等于 (nums[i] - t) 的最小元素,使用 ceiling 变量进行保存。
- 如果 ceiling 不为空,并且它的值小于等于 (nums[i] + t),则说明找到了满足条件的两个元素,返回 true。
- 否则,将当前元素 (long) nums[i] 添加到 set 中。
- 如果当前索引 i 大于等于 k,即窗口大小已经达到了 k+1,则需要移除窗口最左边的元素 (long) nums[i - k],以保持窗口大小不超过 k。
- 最后,如果遍历完整个数组都未找到符合条件的元素对,则返回 false。
这段代码利用了 TreeSet 的排序和查找特性,通过维护一个窗口大小为 k 的集合,在遍历过程中判断是否存在满足条件的元素对。时间复杂度为 O(nlogk),其中 n 是数组的长度。
代码实现(java)
1 |
|
代码实现(golang)
1 |
|
这个优化的实现使用了桶排序的思想,将数据根据具有固定范围的桶进行分组。每个桶的范围是 t+1,其中 t 是差值范围。
在遍历数组时,对于每个元素,我们计算它所属的桶号,并检查当前桶和相邻的桶中是否存在满足条件的元素。如果存在,即找到了满足条件的两个元素,返回 true。
然后,将当前元素添加到对应的桶中,并在超过索引范围 k 后删除最早添加的元素所属的桶。
相比之前的实现,这个优化的版本避免了使用 TreeSet 的模拟和循环遍历差值范围内的所有值,而是根据桶的范围来判断是否存在符合条件的元素对。这样可以提高算法的效率。
该优化版本的时间复杂度为 O(n),其中 n 是数组的长度,与差值范围 t 无关。
剑指 Offer II 057. 存在重复元素 III
https://liuxx1106.github.io/2023/09/25/algorithm-offer057/