二叉树_存在重复元素/是否为平滑二叉树
Posted NLPer项目算法实战
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树_存在重复元素/是否为平滑二叉树相关的知识,希望对你有一定的参考价值。
"""
存在重复元素 III
给你一个整数数组 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
0 <= k <= 104
0 <= t <= 231 - 1
相关标签
"""
# 方法1暴力求解法
class Solution:
def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
for i in range(len(nums)):
for j in range(i + 1,len(nums)):
if abs(nums[i] - nums[j]) <= t and abs(i - j) <= k:
return True
return False
"""
解题思路,利用桶,O(N)时间复杂度
遍历一遍数组for i in range(len(nums))
对于任意的数nums[i] 利用 nums[i]//(t+1) 就可以把数分到不同的桶中,这些桶的数字分别是 0到t (0号桶) t+1到2t(1号桶) ... nt+1到(n+1)t
为啥这样整呢?
桶内元素绝对满足 abs(nums[i] - nums[j]) <= t
相邻的桶有可能出现 abs(nums[i] - nums[j]) <= t
不相邻的桶一定不会出现 abs(nums[i] - nums[j]) <= t , 你可以想一下0号桶和2号桶,他们最大值和最小值差了t+1
这就是为啥//t+1的原因
好,还有个条件:abs(i - j) <= k
思考一下:在i越过k之前,需要考虑这个条件吗?
不需要,因为总共长度最多k+1,再怎么减也是小于等于k的。
所以在越过k之前,我们根据nums[i]//(t+1)依次把nums[i]往总桶里加。
这里可以使用哈希表来存桶号:桶值,如果出现:
要加入的这个桶值存在,说明之前有某个j,使得nums[j]//(t+1)==nums[i]//(t+1),根据上面第一条那就返回True(所以根据这条,这些桶最多只有一个数,如果有俩早就返回True了)。
如果不存在,加入哈希表 (key:value)为 (桶值:nums[i]) , 然后跟相邻的桶的value比较一下,如果满足abs(nums[i] - nums[j]) <= t ,返回True。
i越过k了呢?
很简单,那么对于nums[i-k],他已经不在我们考虑范围了,所以把这个数带来的操作销毁掉,也就是把桶nums[i]//(t+1)删除掉即可
"""
# 方法2分桶
class Solution:
def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
all_buckets = {}
bucket_size = t + 1
for i in range(len(nums)):
bucket_num = nums[i] // bucket_size
if bucket_num in all_buckets:
return True
all_buckets[bucket_num] = nums[i]
if (bucket_num - 1) in all_buckets and abs(all_buckets[bucket_num - 1] - nums[i]) <= t:
return True
if (bucket_num + 1) in all_buckets and abs(all_buckets[bucket_num + 1] - nums[i]) <= t:
return True
if i >= k:
all_buckets.pop(nums[i - k] // bucket_size)
return False
# 解题思路,利用桶,O(N)时间复杂度
# 二叉搜索树
from sortedcontainers import SortedSet
class Solution:
def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
sorted_set = SortedSet()
for i in range(len(nums)):
num = nums[i]
# find the successor of current element
if sorted_set and sorted_set.bisect_left(num) < len(sorted_set):
if sorted_set[sorted_set.bisect_left(num)] <= num + t:
return True
# find the predecessor of current element
if sorted_set and sorted_set.bisect_left(num) != 0:
if num <= sorted_set[sorted_set.bisect_left(num) - 1] + t:
return True
sorted_set.add(num)
if len(sorted_set) > k:
sorted_set.remove(nums[i - k])
return False
"""
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点的左右两个子树的高度差的绝对值不超过 1 。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:true
示例 2:
输入:root = [1,2,2,3,3,null,null,4,4]
输出:false
示例 3:
输入:root = []
输出:true
树结构中的常见用语:
节点的深度 - 从树的根节点到该节点的边数
节点的高度 - 该节点和叶子之间最长路径上的边数
树的高度 - 其根节点的高度
一个高度平衡的二叉搜索树(平衡二叉搜索树)是在插入和删除任何节点之后,可以自动保持其高度最小。也就是说,有 N 个节点的平衡二叉搜索树,它的高度是 logN 。并且,每个节点的两个子树的高度不会相差超过 1。
为什么是 logN 呢?
一个高度为 h 的二叉树
换言之,一个有 N 个节点,且高度为 h 的二叉树
所以:
我们已经介绍过了二叉树及其相关操作, 包括搜索、插入、删除。当分析这些操作的时间复杂度时,我们需要注意的是树的高度是十分重要的考量因素。以搜索操作为例,如果二叉搜索树的高度为 h ,则时间复杂度为 O(h) 。二叉搜索树的高度的确很重要。
所以,我们来讨论一下树的节点总数 N 和高度 h 之间的关系。对于一个平衡二叉搜索树, 我们已经在前文中提过,
但一个普通的二叉搜索树,在最坏的情况下,它可以退化成一个链。
因此,具有 N 个节点的二叉搜索树的高度在 logN 到 N 区间变化。也就是说,搜索操作的时间复杂度可以从 logN 变化到 N 。这是一个巨大的性能差异。
所以说,高度平衡的二叉搜索树对提高性能起着重要作
"""
# 方法1自底至顶
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
return self.recur(root) != -1
def recur(self, root):
if not root:
return 0
left = self.recur(root.left)# 相当于子树一路到底
if left == -1:
return -1
right = self.recur(root.right)# 相当于子树一路到底
if right == -1:
return -1
return max(right, left) + 1 if abs(left - right) < 2 else -1 # 相当于子树一路到底 往回撤的时候再判断,一旦不满足提前终止
"""
复杂度分析:
时间复杂度 O(N): N 为树的节点数;最差情况下,需要递归遍历树的所有节点。
空间复杂度 O(N): 最差情况下(树退化为链表时),系统递归需要使用 O(N)的栈空间。
"""
# 方法2自顶至底
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
if not root:
return True
return abs(self.depth(root.left) - self.depth(root.right)) <= 1 and self.isBalanced(root.left) and self.isBalanced(root.right)
def depth(self, root):
if not root:
return 0
return max(self.depth(root.left), self.depth(root.right)) + 1
"""
复杂度分析:
时间复杂度O(Nlog2N): 最差情况下, isBalanced(root) 遍历树所有节点,占用 O(N) ;判断每个节点的最大高度 depth(root) 需要遍历 各子树的所有节点 ,子树的节点数的复杂度为 O(log2N) 。
空间复杂度 O(N): 最差情况下(树退化为链表时),系统递归需要使用 O(N) 的栈空间。
"""
以上是关于二叉树_存在重复元素/是否为平滑二叉树的主要内容,如果未能解决你的问题,请参考以下文章