Tree and Divide Conquer

本文深入探讨了二叉树的性质与分治策略在算法设计中的应用,通过LeetCode #114题“二叉树展开为链表”的案例,详细解析了如何运用递归算法将树结构转化为链表,重点讲解了从最简情况出发逐步构建复杂解决方案的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


title: Tree and Divide Conquer
date: 2020-03-24 20:11:09
tags: Algorithm


Tree and Divide Conquer

最近做二叉树相关的题,被递归搞的晕头转向。

一、树的性质

参考:Tree总结

由于树的结构,这种数据结构很适合用分治(Divide Conquer)

Divide and Conquer模版

递归算法模版;

def traversal(root):
	# base case(none or leaf)
	if not root:
		# do sth
	
	# divide
	left = traversal(root.left)
	right = traversal(root.right)
	
	# Conquer
	res = # merge 
	return res

114 Flatten Binary Tree to Linked List

以 leetcode #114题为例

1)从最简单的case开始

simplest case,树只有一个元素1,直接返回;

# simplest case:
    1
# 两个元素:
    1
   / 
  2   
  ########   
    1
     \
      2
# 三个元素:
    1
   / \
  2   3
# N 个元素
     1
   /   \
LTree  RTree
例子:
    1
   / \
  2   5
 / \   \
3   4   6

当有两个元素时:

def flatten2(root):
    left = root.left
    right = root.right
    if left:
        root.right = left
        root.left = None

当有三个元素时:

def flatten3(root):
    # divide 
    left = root.left
    right = root.right
    # merge
    if left:
        root.right = left
        root.left = None
    if right:
        left.right = right
2)一般case

可以将其分为 左子树和右子树,(假设左右都为三个元素(base case),我们可以用上面的程序处理好)。假设左右子树都已经处理完毕。

def flatten(root):
	# base case(none)
    if not root:
        return
    # leaf node
    if not root.left and not root.right:
        return root
    # divide
   	left = root.left
    right = root.right
    # conquer 处理左右子树
    flatten(left)
    flatten(right)
    # merge
    if left:
        root.right=left
        root.left = None
    if right:
        ...
3) merge

如何把子问题的解merge原问题的解?

把子问题的解 merge成问题的解时需要解决一个问题,即如何将右子树链接到左子树的后面?

  1. 左子树的哪个节点去链接右子树根节点?
  2. 如何确定这个节点的位置

根据题意知道,最终生成 linked list 顺序是先序遍历的顺序,故将左子树最右边的叶子节点链接到右子树的根节点;使用python中的全局变量指向当前根节点下的最右叶子节点。

算法:

 prev = None
 def func(root):
 	if root is leaf:
 		# prev 指向左子树的最右子节点
 		prev=root
    left = root.left
    right = root.right
    # 递归处理左子树
    func(left)
    # 如果左子树存在
    if left:
    	# 将root的右子节点指向左子树
    	root.right = left
    	root.left = None
    	# 将左子树最右边的叶子节点指向右子树
    	prev.right = right
    # 递归处理右子树
    func(right)

最终AC的代码:

Python3代码:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def __init__(self):
        self.prev = None
    def flatten(self, root: TreeNode) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        # base case
        if not root:
            return
        if not root.left and not root.right:
            self.prev=root
            return
       	# divide
        left = root.left
        right = root.right
        # conquer
        self.flatten(left)
        # merge
        if left:
            root.right, root.left = left, None
            self.prev.right = right
        # conquer
        self.flatten(right)

代码精简版:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def __init__(self):
        self.prev = None
    def flatten(self, root: TreeNode) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        if not root:
            return
        self.prev = root
        right = root.right
        self.flatten(root.left)
        root.right, root.left=root.left, None
        self.prev.right = right
        self.flatten(right)

从以上代码可以看出,其实就是对 Tree 进行先序遍历,同时将全局变量用作指针

这道题还有其他思路,(修改版的后序遍历)遍历顺序是右子树->左子树->根节点。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def __init__(self):
        self.prev = None
    def flatten(self, root: TreeNode) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        if not root:
            return None
        self.flatten(root.right)
        self.flatten(root.left)

        root.right = self.prev
        root.left = None
        self.prev = root
总结
  1. 对树进行divide conquer ,要把所有的最简单case列出来分析
  2. 将树分为子问题一般比较容易,关键如何将子问题的解merge成原问题的解!
  3. python的全局变量的使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值