1. 最大二叉树(leetcode 654)
这题和我们day17 二叉树04里面的用后序中序数组构造二叉树的思路基本一模一样。
同样也是用我们的递归法。先找出最大值,然后把最大值设置为当前节点,然后用最大值把数组分为左右两部分,然后对左右两部分进行递归。代码如下。
class Solution:
def constructMaximumBinaryTree(self, nums: List[int]) -> Optional[TreeNode]:
if len(nums) == 0:
return None
max_val = max(nums)
position = nums.index(max_val)
root = TreeNode(max_val)
left_nums = nums[:position]
right_nums = nums[position+1:]
root.left = self.constructMaximumBinaryTree(left_nums)
root.right = self.constructMaximumBinaryTree(right_nums)
return root
2. 合并二叉树(leetcode 617)
这题前中后序遍历都可以的,没啥限制,因为都要遍历到也都要处理到。
我们以前序遍历为例,这边过一下递归三部曲:
1.确认参数和返回值。参数就是两棵树相同位置的根节点,返回值就是合并的当前位置根节点。
2. 确认终止条件。当两棵树都没有,终止为None。当其中一颗树没有,则直接返回另一棵树。像这种有两棵树的题,我们一定要考虑好其中一颗树为空的情况,做到面面俱到。
3. 确认单层递归逻辑。就按中左右的顺序遍历递归就好。
class Solution:
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
if not root1 and not root2:
return None
if not root1: return root2
if not root2: return root1
value1 = root1.val
value2 = root2.val
current = value1 + value2
root = TreeNode(current)
root.left = self.mergeTrees(root1.left, root2.left)
root.right = self.mergeTrees(root1.right, root2.right)
return root
这题不太好用stack迭代写,因为有的节点是只有一个树有的,我们不太好处理。递归我们才能统一处理。
当然我们也可以用queue的方式写,在root1这颗树上根据root2这颗树的节点来改动,这样写更省空间,时间复杂度是一样的。这应该是本题比较好的一个写法。
class Solution:
def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
if not root1:
return root2
if not root2:
return root1
queue = deque()
queue.append(root1)
queue.append(root2)
while queue:
node1 = queue.popleft()
node2 = queue.popleft()
# 更新queue
# 只有两个节点都有左节点时, 再往queue里面放.
if node1.left and node2.left:
queue.append(node1.left)
queue.append(node2.left)
# 只有两个节点都有右节点时, 再往queue里面放.
if node1.right and node2.right:
queue.append(node1.right)
queue.append(node2.right)
# 更新当前节点. 同时改变当前节点的左右孩子.
node1.val += node2.val
if not node1.left and node2.left:
node1.left = node2.left
if not node1.right and node2.right:
node1.right = node2.right
return root1
3. 二叉搜索树中的搜索(leetcode 700)
非常简单的一道题,给定了binary tree,我们直接利用binary tree的特性递归就好了。
1. 参数和返回值:参数为节点和value,返回值为满足目标的树
2. 终止条件:若为空节点,就代表走到头了,返回None
3. 单层递归逻辑,按照binary tree的特性二分往下递归就好。
class Solution:
def searchBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
if not root:
return None
current_val = root.val
if root.val == val: return root
if root.val > val: return self.searchBST(root.left, val)
if root.val < val: return self.searchBST(root.right, val)
同样的这题我们也可以用stack或者直接用节点来迭代。因为我们想要利用二叉搜索树得到特性,所以我们不能使用queue来层序遍历。
class Solution:
def searchBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
while root:
if val < root.val: root = root.left
elif val > root.val: root = root.right
else: return root
return None
4. 验证二叉搜索树(leetcode 98)
这道题我们要先确认用什么遍历方式。
要知道在中序遍历下,输出的二叉搜索树节点的数值是有序序列。这是个很重要的特性,左中右从小到达排呗。所以我们只需要验证中序序列是否递增就可以了。
class Solution:
def traversal(self, root):
if not root:
return
self.traversal(root.left)
self.nums.append(root.val)
self.traversal(root.right)
def isValidBST(self, root: Optional[TreeNode]) -> bool:
self.nums = []
self.traversal(root)
for i in range(1,len(self.nums)):
if self.nums[i] <= self.nums[i-1]:
return False
return True
这是一个很讨巧的方法,但我们也是要记住这层中序和二叉搜索树的关系的。
同时我们也可以用迭代法,中序迭代,中间遇到更大的值,直接return False。这个方法会省点时间,因为平均情况是不用遍历完整个树的。
class Solution:
def isValidBST(self, root: Optional[TreeNode]) -> bool:
stack = []
cur = root
pre = None # 记录前一个节点
while cur is not None or len(stack) > 0:
if cur is not None:
stack.append(cur)
cur = cur.left # 左
else:
cur = stack.pop() # 中
if pre is not None and cur.val <= pre.val:
return False
pre = cur # 保存前一个访问的结点
cur = cur.right # 右
return True