这道题解法太多了,先写自己的解法,然后摘录一些精妙的写法
递归分析
按照之前文章的思路递归的一些例子,稍微分析一下就能写出代码
- 边界情况
root为空或者root无左右孩子 - 一般操作
展开左子树得到L,展开右子树得到R
然后寻找root的前驱结点t,将t的右指针指向R
将root.left置为空,root.right置为L - 返回部分
返回拼接后的root即可
class Solution:
def flatten(self, root: TreeNode) -> None:
if not root or (not root.left and not root.right):
return root # 边界情况
# 展开左右子树
L = self.flatten(root.left)
R = self.flatten(root.right)
# L不为空,拼接
if L != None:
t = L # t找到root的前驱结点
while t and t.right!=None:
t = t.right
# 拼接 root.right -> L -> R
t.right = R
root.left = None
root.right = L
# 返回展开的结果
return root
利用栈迭代展开
展开的规则是:
root的左子树为空,右子树是先序遍历左右子树得到的顺序,重复上述规则得到展开后的链表
那么我们可以用先序迭代来完成这个过程
- 每次遇到一个节点,将它不为空的右孩子、左孩子入栈
- 用pre,cur标记前一个结点和当前节点
- 从栈顶弹出一个元素,此时它为cur
- 每次按照规则修改:pre的左指针为空,右指针指向cur,更新pre为cur
class Solution:
def flatten(self, root: TreeNode) -> None:
if not root:
return root # 边界情况
s = [root]
pre,cur = None,None
while s:
cur = s.pop()
if pre:
pre.left = None
pre.right = cur
if cur.right:
s.append(cur.right)
if cur.left:
s.append(cur.left)
pre = cur
# 返回展开的结果
return root
O(1)的迭代展开,和解法1思想相同
解法1里面我们寻找root的前驱来拼接,这里我们可以把递归改成迭代
class Solution:
def flatten(self, root: TreeNode) -> None:
cur = root
while cur:
# 处理左子树的情况
if cur.left:
# pre 对应cur的后继结点,nxt是拼接后cur应该移动的位置
pre = nxt = cur.left
while pre.right:
pre = pre.right
# 把左子树拼接到右子树上,修改cur的右指针
cur.left = None
pre.right = cur.right
cur.right = nxt
# 向后移动
cur = cur.right
return root
细节不描述了,看一下代码就懂了
修改last指针,后序递归
相同的思想在dp里面自底向上很常见
class Solution:
def __init__(self):
self.last = None
def flatten(self, root: TreeNode) -> None:
if not root:
return
self.flatten(root.right)
self.flatten(root.left)
root.left = None
root.right = self.last
self.last = root
不是很好描述,思想就是从后往前构造链表,不断链接最后一个指针,然后更新last