0220. 存在重复元素 III
大约 5 分钟
0220. 存在重复元素 III
- 标签:数组、桶排序、有序集合、排序、滑动窗口
- 难度:中等
题目链接
题目大意
描述:给定一个整数数组 ,以及两个整数 、。
要求:判断数组中是否存在两个不同下标的 和 ,其对应元素满足 ,同时满足 。如果满足条件则返回 True
,不满足条件返回 False
。
说明:
- 。
- 。
- 。
- 。
示例:
- 示例 1:
输入:nums = [1,2,3,1], k = 3, t = 0
输出:True
- 示例 2:
输入:nums = [1,0,1,1], k = 1, t = 2
输出:True
解题思路
题目中需要满足两个要求,一个是元素值的要求() ,一个是下标范围的要求()。
对于任意一个位置 来说,合适的 应该在区间 内,同时 值应该在区间 内。
最简单的做法是两重循环遍历数组,第一重循环遍历位置 ,第二重循环遍历 的元素,判断是否满足 。但是这样做的时间复杂度为 ,其中 是数组 的长度。
我们需要优化一下检测相邻 个元素是否满足 的方法。有两种思路:「桶排序」和「滑动窗口(固定长度)」。
思路 1:桶排序
- 利用桶排序的思想,将桶的大小设置为 。只需要使用一重循环遍历位置 ,然后根据 ,从而决定将 放入哪个桶中。
- 这样在同一个桶内各个元素之间的差值绝对值都小于等于 。而相邻桶之间的元素,只需要校验一下两个桶之间的差值是否不超过 。这样就可以以 的时间复杂度检测相邻 个元素是否满足 。
- 而 条件则可以通过在一重循环遍历时,将超出范围的 从对应桶中删除,从而保证桶中元素一定满足 。
具体步骤如下:
- 将每个桶的大小设置为 。我们将元素按照大小依次放入不同的桶中。
- 遍历数组 中的元素,对于元素$ nums[i]$ :
- 如果 放入桶之前桶里已经有元素了,那么这两个元素必然满足 ,
- 如果之前桶里没有元素,那么就将 放入对应桶中。
- 再判断左右桶的左右两侧桶中是否有元素满足 。
- 然后将 之前的桶清空,因为这些桶中的元素与 已经不满足 了。
- 最后上述满足条件的情况就返回
True
,最终遍历完仍不满足条件就返回False
。
思路 1:代码
class Solution:
def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
bucket_dict = dict()
for i in range(len(nums)):
# 将 nums[i] 划分到大小为 t + 1 的不同桶中
num = nums[i] // (t + 1)
# 桶中已经有元素了
if num in bucket_dict:
return True
# 把 nums[i] 放入桶中
bucket_dict[num] = nums[i]
# 判断左侧桶是否满足条件
if (num - 1) in bucket_dict and abs(bucket_dict[num - 1] - nums[i]) <= t:
return True
# 判断右侧桶是否满足条件
if (num + 1) in bucket_dict and abs(bucket_dict[num + 1] - nums[i]) <= t:
return True
# 将 i - k 之前的旧桶清除,因为之前的桶已经不满足条件了
if i >= k:
bucket_dict.pop(nums[i - k] // (t + 1))
return False
思路 1:复杂度分析
- 时间复杂度:。 是给定数组长度。
- 空间复杂度:。桶中最多包含 个元素。
思路 2:滑动窗口(固定长度)
- 使用一个长度为 的滑动窗口,每次遍历到 时,滑动窗口内最多包含 之前最多 个元素。只需要检查前 个元素是否在 区间内即可。
- 检查 个元素是否在 区间,可以借助保证有序的数据结构(比如
SortedList
)+ 二分查找来解决,从而减少时间复杂度。
具体步骤如下:
- 使用有序数组类 维护一个长度为 的窗口,满足数组内元素有序,且支持增加和删除操作。
- 、 都指向序列的第一个元素。即:
left = 0
,right = 0
。 - 将当前元素填入窗口中,即
window.add(nums[right])
。 - 当窗口元素大于 个时,即当 时,移除窗口最左侧元素,并向右移动 。
- 当窗口元素小于等于 个时:
- 使用二分查找算法,查找 在 中的位置 。
- 判断 与相邻位置上元素差值绝对值,若果满足 或者 时返回
True
。
- 向右移动 。
- 重复 步,直到 到达数组末尾,如果还没找到满足条件的情况,则返回
False
。
思路 2:代码
from sortedcontainers import SortedList
class Solution:
def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
size = len(nums)
window = SortedList()
left, right = 0, 0
while right < size:
window.add(nums[right])
if right - left > k:
window.remove(nums[left])
left += 1
idx = bisect.bisect_left(window, nums[right])
if idx > 0 and abs(window[idx] - window[idx - 1]) <= t:
return True
if idx < len(window) - 1 and abs(window[idx + 1] - window[idx]) <= t:
return True
right += 1
return False
思路 2:复杂度分析
- 时间复杂度:。
- 空间复杂度:。