题目链接

LeetCode

题目描述

给你二叉树的根结点 root ,请你将它展开为一个单链表:

  • 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null
  • 展开后的单链表应该与二叉树 先序遍历 顺序相同。

示例 1:

114. 二叉树展开为链表 - 图1

输入: root = [1,2,5,3,4,null,6]
输出: [1,null,2,null,3,null,4,null,5,null,6]

示例 2:

输入: root = []
输出: []

示例 3:

输入: root = [0]
输出: [0]

提示:

  • 树中结点数在范围 [0, 2000]
  • -100 <= Node.val <= 100

进阶: 你可以使用原地算法(O(1) 额外空间)展开这棵树吗?

解题思路

方法一:前序遍历

将二叉树展开为单链表之后,单链表中的节点顺序即为二叉树的前序遍历访问各节点的顺序。因此,可以对二叉树进行前序遍历,获得各节点被访问到的顺序。由于将二叉树展开为链表之后会破坏二叉树的结构,因此在前序遍历结束之后更新每个节点的左右子节点的信息,将二叉树展开为单链表。

  1. /**
  2. * Definition for a binary tree node.
  3. * struct TreeNode {
  4. * int val;
  5. * TreeNode *left;
  6. * TreeNode *right;
  7. * TreeNode() : val(0), left(nullptr), right(nullptr) {}
  8. * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
  9. * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
  10. * };
  11. */
  12. class Solution {
  13. public:
  14. void flatten(TreeNode* root) {
  15. if(root==nullptr)
  16. return;
  17. recur(root);
  18. int n = vec.size();
  19. for(int i=0;i<n-1;i++){
  20. vec[i]->right = vec[i+1];
  21. vec[i]->left = nullptr;
  22. }
  23. }
  24. void recur(TreeNode* root){
  25. if(root==nullptr)
  26. return;
  27. vec.push_back(root);
  28. recur(root->left);
  29. recur(root->right);
  30. }
  31. private:
  32. vector<TreeNode*> vec;
  33. };
  • 时间复杂度 O(n)
  • 空间复杂度 O(n)

方法二:寻找前驱节点

注意到前序遍历访问各节点的顺序是根节点、左子树、右子树。

  • 如果一个节点的左子节点为空,则该节点不需要进行展开操作。
  • 如果一个节点的左子节点不为空,则该节点的左子树中的最后一个节点被访问之后,该节点的右子节点被访问。该节点的左子树中最后一个被访问的节点是左子树中的最右边的节点,也是该节点的前驱节点。

因此,问题转化成寻找当前节点的前驱节点。

具体做法是
对于当前节点,如果其左子节点不为空,

  • 则在其左子树中找到最右边的节点,作为前驱节点,
  • 将当前节点的右子节点赋给前驱节点的右子节点,
  • 然后将当前节点的左子节点赋给当前节点的右子节点,并将当前节点的左子节点设为空。
  • 对当前节点处理结束后,继续处理链表中的下一个节点,直到所有节点都处理结束。

image.png
image.png
image.png
image.png
image.png

  1. /**
  2. * Definition for a binary tree node.
  3. * struct TreeNode {
  4. * int val;
  5. * TreeNode *left;
  6. * TreeNode *right;
  7. * TreeNode() : val(0), left(nullptr), right(nullptr) {}
  8. * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
  9. * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
  10. * };
  11. */
  12. class Solution {
  13. public:
  14. void flatten(TreeNode* root) {
  15. if(root==nullptr)
  16. return;
  17. TreeNode* cur = root;
  18. while(cur!=nullptr){
  19. if(cur->left!=nullptr){
  20. // 中序遍历下一个结点为左子树结点
  21. TreeNode* next = cur->left;
  22. // 找出左子树最右边结点,也是中序遍历左子树最后一个结点
  23. TreeNode* pre = next;
  24. while(pre->right!=nullptr){
  25. pre = pre->right;
  26. }
  27. // 中序遍历左子树最后一个结点的右子树指向右子树第一个结点(连接左右子树结点链表)
  28. pre->right = cur->right;
  29. // 当前结点的左子树设为null,右子树指向下一个结点(左子树第一个结点)
  30. cur->left = nullptr;
  31. cur->right = next;
  32. }
  33. // 指向下一个中序遍历结点
  34. cur = cur->right;
  35. }
  36. }
  37. };
  • 时间复杂度 O(n)
  • 空间复杂度 O(1)