代码随想录算法训练营第十五天(二叉树篇)|Leetcode654最大二叉树,Leetcode617合并二叉树,Leetcode700二叉搜索树中的搜索,Leetcode98验证二叉搜索树
Leetcode 654 最大二叉树
题目链接: 最大二叉树
给定一个不含重复元素的整数数组,据此构建一棵最大二叉树,方法如下:
- 找出该数组中最大的元素,为其创建一个相应二叉树节点。该元素将该数组分割成两个部分。
- 从左部分中选取其中最大的元素,作为当前节点的左孩子节点
- 从右部分中选取其中最大的元素,作为当前节点的右孩子节点,重复上述操作直至处理完数组中所有元素。
思路: 整理上述流程,我们知道,我们需要不断找出数组片段中最大值,创建相应节点,并递归处理剩下的区间。
有了昨天处理 从中序遍历和后续遍历构造二叉树(Leetcode 106)
的经验,我们知道,传递区间最佳的方式不是再创建额外的数组,而是传递下标和原数组。因此此处我们采用传递下标的方式解决相应问题。
递归三部曲分析如下:
- 递归函数参数与返回值
递归函数参数为数组整体,以及用于分割数组的相应下标。返回值为创建好的相应二叉树节点 - 递归终止条件:
当给定区间为空时,终止遍历 - 每层递归操作:
找出区间内最大值,利用该最大值将区间分割成两个部分。并将这两个部分的返回值分别作为当前节点的左右子节点。
具体代码实现
class Solution:
def buildMaximumBinaryTree(self, nums: List[int], startIdx: int, endIdx: int) -> Optional[TreeNode]:
# 由于坚持左闭右开区间,因此当起始下标大于等于终止下标时,停止继续向下递归。
if startIdx >= endIdx:
return
# 找出给定区间内的最大值
maxIdx, maxElement = startIdx, nums[startIdx]
for i in range(startIdx, endIdx):
if nums[i] > maxElement:
maxIdx, maxElement = i, nums[i]
root = TreeNode(maxElement)
leftStartIdx = startIdx
leftEndIdx = maxIdx
rightStartIdx = maxIdx + 1
rightEndIdx = endIdx
if leftEndIdx - leftStartIdx > 0:
root.left = self.buildMaximumBinaryTree(nums, leftStartIdx, leftEndIdx)
if rightEndIdx - rightStartIdx > 0:
root.right = self.buildMaximumBinaryTree(nums, rightStartIdx, rightEndIdx)
return root
def constructMaximumBinaryTree(self, nums: List[int]) -> Optional[TreeNode]:
# 坚持左闭右开区间
root = self.buildMaximumBinaryTree(nums, 0, len(nums))
return root
Leetcode 617 合并二叉树
题目链接: 合并二叉树
给定两棵二叉树,将其中的节点进行合并,返回合并后二叉树的根节点。
Example1:
1 2 3
/ \ / \ / \
3 2 + 1 3 = 4 5
/ \ \ / \ \
5 4 7 5 4 7
当对应节点均存在时,合并后节点的值相当于对应节点值之和
当对应节点存在一个时,合并后节点的值相当于存在的节点值
思路: 合并二叉树时,我们可以在其中一棵二叉树中对节点的值原地进行修改,完成修改后,直接返回对应二叉树的根节点即可。
通过递归三部曲进行分析:
- 递归函数参数以及返回值:
递归函数参数为当前正在遍历的两棵二叉树的对应节点,返回值应该为两棵二叉树合并后的节点 - 递归终止条件
正在遍历的两棵二叉树的相应节点均为空时,终止递归操作。 - 每层递归操作
若两棵二叉树的相应节点均存在,则将节点值相加,创建一个新节点。若仅一棵二叉树的相应节点存在,则在其中一棵二叉树的节点上原地进行修改。
具体代码实现
class Solution:
def merge(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
# 对应节点均不存在,返回空
if root1 is None and root2 is None:
return
# 两个节点均存在,将节点值相加
if root1 and root2:
root1.val += root2.val
root1.left = self.merge(root1.left, root2.left)
root1.right = self.merge(root1.right, root2.right)
return root1
# 返回存在的相应节点
if root1:
return root1
return root2
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
return self.merge(root1, root2)
Leetcode 700 二叉搜索树中的搜索
题目链接: 二叉搜索树中的搜索
在一棵给定的二叉搜索树中,检索给定的值是否出现过。若给定的值在二叉树中出现过则返回相应节点,否则返回空
思路: 首先复习二叉搜索树的概念。
二叉搜索树,即为根节点严格大于左子树中的所有节点,严格小于右子树中所有节点,且左右子树均递归地符合这一要求的一类二叉树。通过二叉搜索树搜索特定的值,时间复杂度为 O(logn)
利用递归三部曲进行分析:
- 递归函数参数与返回值:
递归函数参数为当前遍历的节点以及待查找的目标值,返回值为相应的二叉树节点 - 递归终止条件:
当前节点为空时,返回空节点,终止递归操作。 - 每层递归操作:
比较当前节点的值与目标值,若相等,则返回相应节点,若不相等,则继续深度递归。
具体代码实现
# 递归法
class Solution:
def search(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
if root is None:
return
if root.val > val:
return self.search(root.left, val)
if root.val < val:
return self.search(root.right, val)
return root
def searchBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
return self.search(root, val)
# 迭代法
class Solution:
def searchBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
from collections import deque
if root is None:
return
myQueue = deque()
myQueue.append(root)
while myQueue:
node = myQueue.popleft()
if node.val == val:
return node
# 利用二叉搜索树中的特性,将相应节点加入到队列中
if node.val > val and node.left:
myQueue.append(node.left)
if node.val < val and node.right:
myQueue.append(node.right)
return
Leetcode 98 验证二叉搜索树
题目链接: 验证二叉搜索树
给定一棵二叉树,判断该二叉树是否为二叉搜索树。
思路: 本题中一个常见的误区是,直接尝试使用递归法,通过左右子树是否满足二叉搜索树的条件,来判断以当前节点为根节点的二叉树是否为二叉搜索树。然而这种思路并不能够处理以下的情况:
5
/ \
4 6
/ \
3 7
由于 3
< 5
,因此该二叉树不是二叉搜索树。
再回忆二叉树的特性,二叉树的根节点大于左子树中的所有节点,小于右子树中的所有节点。因此,我们可以尝试通过中序遍历,获取当前二叉树的数组。若当前二叉树确实是二叉搜索树,则该数组应该是严格递增的。因此,我们可以通过判断当前数组是否严格递增,来判断当前二叉树是否为二叉搜索树。
具体代码实现
class Solution:
def inorderTraverse(self, cur: Optional[TreeNode]) -> List[int]:
result = []
myStack = []
if cur is None:
return result
myStack.append([cur, False])
while myStack:
node, visited = myStack.pop()
if visited:
result.append(node.val)
continue
if node.right:
myStack.append([cur.right, False])
myStack.append([cur, True])
if node.left:
myStack.append([cur.left, False])
return result
def isValidBST(self, root: Optional[TreeNode]) -> bool:
inorder = self.inorderTraverse(root)
# 验证中序数组是否严格单调递增
for i in range(1, len(inorder)):
if inorder[i] <= inorder[i-1]:
return False
return True