一、669. 修剪二叉搜索树
这道题目比较难 ,比 添加增加和删除节点难的多,建议先看视频理解。题目链接/文章讲解: 代码随想录
视频讲解: 你修剪的方式不对,我来给你纠正一下!| LeetCode:669. 修剪二叉搜索树_哔哩哔哩_bilibili
1. 常见误区及代码
常见的错误思路是判断节点值是否在区间范围内,如果不在范围内,直接返回null,砍掉了这颗节点及其下方的树。
然而,需要注意的是,这是一颗二叉搜索树,如果节点值不在范围,那么应该删除的是节点及其左子树,而它的右子树还需要继续遍历,看是否有满足条件的。
2. 正确的代码实现
(1)确定递归函数的参数和返回值:参数是根节点、左区间、右区间,返回的是修建后树的根节点。
(2)确定终止条件:根节点为空,直接返回null。
如果当前节点的值是小于左区间的,那么它的右子树可能存在满足范围的元素,所以需要在这个节点的右子树去遍历,最后返回新右子树的根节点。
如果当前节点的值是大于右区间的,那么它的左子树可能存在满足范围的元素,所以需要在这个节点的左子树去遍历,最后返回新左子树的根节点。
(3)确定单层递归:根节点的左子树=向左递归,根节点的右子树=向右递归。
(4)最后返回根节点。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
if root is None:
return None
if root.val < low:
left = self.trimBST(root.right, low, high)
return left
if root.val > high:
right = self.trimBST(root.left, low, high)
return right
root.left = self.trimBST(root.left, low, high)
root.right = self.trimBST(root.right, low, high)
return root
二、108.将有序数组转换为二叉搜索树
本题就简单一些,可以尝试先自己做做。
1. 题意
(1)为什么一定要构造成平衡二叉搜索树?
因为任何一个有序数组,都可以将其构造为一个链式的二叉搜索树(相当于一条斜线),且满足二叉树的特性,那么本题将没有意义。
2. 整体思路
找到数组的中间点,构造左区间和右区间,递归左区间构造为左子树,递归右区间构造为右子树。也就是数组的中点作为树的中节点,这样才能保证二叉树是平衡的。
如果数组是偶数,那么取左侧/右侧节点作为中节点都可以;如果数组是奇数,那么直接取中间节点。
3. 代码实现
(1)定义递归函数的返回值和参数:传入数组、左区间点和右区间点(数组下标),返回值为根节点。此处需要注意区间的开闭,我们在这里定义为左闭右闭。
(2)确定终止条件:如果左区间大于右区间,就是非法区间,返回None;而左区间等于右区间不是非法区间,因为我们定义的是左闭右闭。
(3)单层递归的处理逻辑:
首先找到中间值下标等于左区间+右区间除以2,注意要采用left+(right-left)//2的写法,否则容易超出内存。接下来构造根节点,传入中间节点的数值。
递归左子树,传入的右区间是middle-1,因为我们定义的是闭区间。
递归左子树,传入的左区间是middle+1,因为我们定义的是闭区间。
(4)返回根节点。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def buildTree(self, nums, left, right)->Optional[TreeNode]:
if left > right:
return None
mid = left + (right - left) // 2
root = TreeNode(nums[mid])
root.left = self.buildTree(nums, left, mid-1)
root.right = self.buildTree(nums, mid+1, right)
return root
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
root = self.buildTree(nums, 0, len(nums)-1)
return root
三、538.把二叉搜索树转换为累加树
本题也不难,在 求二叉搜索树的最小绝对差 和 众数 那两道题目 都讲过了 双指针法,思路是一样的。
1. 解题思路
理解题意:
本题是一棵二叉搜索树,例如下图,节点顺序就是二叉搜索树的遍历顺序(左中右),题目要求每个节点值等于节点顺序大于等于它的节点值之和。比如节点5,它的值就等于节点6、7、8的值之和,也就是节点6的值加上节点5本身。
整体思路:整体的遍历顺序是右中左,采用双指针的思路,定义一个cur指针指向当前节点,pre指针指向前一个节点,然后当前节点的值就等于前一个节点的值加当前的值。
2. 代码实现
(1)定义pre表示前一个节点的值,由于从树最右边的节点开始,所以cur一开始指向的就是树最右边的叶子节点,而其前一个节点不存在,所以pre初始化为0,这样cur就等于0加上本身就等于本身的值。
(2)定义函数的参数和返回值,由于本题是遍历这棵二叉树并更新节点的值,所以本题不需要返回值,传入树的根节点。
(3)确定终止条件:遇到空节点就返回空。
(4)单层递归逻辑:遍历顺序-右中左。
1)右:先向右子树进行递归;
2)中:将当前节点的值加上前一个节点的值,也就是pre+cur.val,就将当前节点值更新了,然后将当前节点的新值赋给pre;
3)左:向左子树进行递归。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def __init__(self):
self.pre = 0
def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if root is None:
return root
# right:
self.convertBST(root.right)
# middle:
root.val += self.pre
self.pre = root.val
# left:
self.convertBST(root.left)
return root
四、二叉树总结
好了,二叉树大家就这样刷完了,做一个总结吧
-
涉及到二叉树的构造,无论普通二叉树还是二叉搜索树一定前序,都是先构造中节点。
-
求普通二叉树的属性,一般是后序,一般要通过递归函数的返回值做计算。
-
求二叉搜索树的属性,一定是中序了,要不白瞎了有序性了。
注意在普通二叉树的属性中,我用的是一般为后序,例如单纯求深度就用前序,二叉树:找所有路径 (opens new window)也用了前序,这是为了方便让父节点指向子节点。