LeetCode114:二叉树展开为链表(三解法)

题目LeetCode114

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

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

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

Python解法

解法一(前序遍历)

python 复制代码
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def flatten(self, root: Optional[TreeNode]) -> None:
        """
        Do not return anything, modify root in-place instead.
        """

        preorderList = list()

        def preorder(root: TreeNode):
            if root:
                preorderList.append(root)
                preorder(root.left)
                preorder(root.right)

        preorder(root)
        size = len(preorderList)

        for i in range(1, size):
            pre, cur = preorderList[i - 1], preorderList[i]
            pre.left = None
            pre.right = cur

解法二(遍历并生成)

python 复制代码
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def flatten(self, root: Optional[TreeNode]) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        if not root:
            return
            
        stack = [root]
        pre = None

        while stack:

            cur = stack.pop()

            if pre:
                pre.left = None
                pre.right = cur

            left, right = cur.left, cur.right

            if right:
                stack.append(right)
            if left:
                stack.append(left)
            
            pre = cur

过程演示

解法三(前驱结点)

python 复制代码
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def flatten(self, root: Optional[TreeNode]) -> None:
        """
        Do not return anything, modify root in-place instead.
        """

        cur = root

        while cur:

            if cur.left:
                predecessor = cur.left

                while predecessor:
                    predecessor = precedecessor.right

                predecessor.right = cur.right
                cur.right = cur.left
                cur.left = None

            cur = cur.right

过程演示

Java解法

解法一(前序遍历)

java 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    // 存储前序遍历所有节点
    private List<TreeNode> preList = new ArrayList<>();

    public void flatten(TreeNode root) {
        // 1. 递归前序遍历收集节点
        preOrderTraverse(root);
        int size = preList.size();
        // 2. 遍历列表,拼接成单链表
        for (int i = 1; i < size; i++) {
            TreeNode prev = preList.get(i - 1);
            TreeNode curr = preList.get(i);
            prev.left = null;   // 左指针置空
            prev.right = curr;  // 右指针指向下一节点
        }
    }

    // 递归前序遍历:根 -> 左 -> 右
    private void preOrderTraverse(TreeNode root) {
        if (root == null) return;
        preList.add(root);
        preOrderTraverse(root.left);
        preOrderTraverse(root.right);
    }
}

解法二(遍历并生成)

java 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public void flatten(TreeNode root) {
        if (root == null) return;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        TreeNode prev = null; // 记录上一个处理的节点

        while (!stack.isEmpty()) {
            TreeNode curr = stack.pop();
            // 上一节点指向当前节点
            if (prev != null) {
                prev.left = null;
                prev.right = curr;
            }
            // 先存左右子节点,栈后进先出,先压右再压左保证前序
            TreeNode left = curr.left;
            TreeNode right = curr.right;
            if (right != null) {
                stack.push(right);
            }
            if (left != null) {
                stack.push(left);
            }
            // 更新前驱节点
            prev = curr;
        }
    }
}

解法三(前驱结点)

java 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public void flatten(TreeNode root) {
        TreeNode curr = root;
        // 逐个向右遍历节点
        while (curr != null) {
            // 当前节点存在左子树才需要调整
            if (curr.left != null) {
                // nxt 保存左子树头部
                TreeNode nxt = curr.left;
                TreeNode predecessor = nxt;
                // 找到左子树最右侧节点
                while (predecessor.right != null) {
                    predecessor = predecessor.right;
                }
                // 左子树末尾接上原右子树
                predecessor.right = curr.right;
                // 左子树移到右侧,清空左指针
                curr.left = null;
                curr.right = nxt;
            }
            // 处理下一个节点
            curr = curr.right;
        }
    }
}

C++解法

解法一(前序遍历)

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
private:
    vector<TreeNode*> preList;

    // 前序递归收集节点
    void preOrderTraverse(TreeNode* root) {
        if (!root) return;
        preList.push_back(root);
        preOrderTraverse(root->left);
        preOrderTraverse(root->right);
    }

public:
    void flatten(TreeNode* root) {
        preOrderTraverse(root);
        int size = preList.size();
        // 节点串联成右斜单链表
        for (int i = 1; i < size; ++i) {
            TreeNode* prev = preList[i - 1];
            TreeNode* curr = preList[i];
            prev->left = nullptr;
            prev->right = curr;
        }
    }
};

解法二(遍历并生成)

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    void flatten(TreeNode* root) {
        if (!root) return;
        stack<TreeNode*> stk;
        stk.push(root);
        TreeNode* prev = nullptr;

        while (!stk.empty()) {
            TreeNode* curr = stk.top();
            stk.pop();

            // 拼接前后节点
            if (prev) {
                prev->left = nullptr;
                prev->right = curr;
            }

            // 先右后左入栈,弹出顺序为前序
            TreeNode* left = curr->left;
            TreeNode* right = curr->right;
            if (right) stk.push(right);
            if (left) stk.push(left);

            prev = curr;
        }
    }
};

解法三(前驱结点)

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    void flatten(TreeNode* root) {
        TreeNode* curr = root;
        while (curr) {
            // 存在左子树则重构指针
            if (curr->left) {
                TreeNode* nxt = curr->left;
                TreeNode* predecessor = nxt;
                // 遍历到左子树最右端节点
                while (predecessor->right) {
                    predecessor = predecessor->right;
                }
                // 拼接原右子树
                predecessor->right = curr->right;
                // 左树迁移到右分支
                curr->left = nullptr;
                curr->right = nxt;
            }
            // 向右前进
            curr = curr->right;
        }
    }
};
相关推荐
淡海水6 小时前
13-04-面试-源码级深度追问链
数据结构·unity·面试·c#·游戏引擎·源码·il2cpp
Logic1016 小时前
C语言/数据结构位运算题解:异或XOR找出时尚聚会中的“独特颜色“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
2401_8390805410 小时前
C++常见八股
数据结构·c++·算法
暮雨封夕10 小时前
跳表(Skip List)详解:原理、实现、使用场景与实际应用
数据结构
miller-tsunami10 小时前
排序的相关知识点
数据结构·排序算法
Logic10115 小时前
C语言/数据结构滑动窗口题解:替换k个字符后的最长连续相同字符子串(LeetCode 424)
c语言·数据结构·字符串·滑动窗口·时间复杂度·频率统计·算法题
程序员阿鹏16 小时前
简单介绍一下软引用
java·开发语言·jvm·数据结构·后端
爱奥尼欧17 小时前
【C++】map、set 的底层是什么?红黑树五条性质、插入旋转到模拟实现
开发语言·数据结构·c++
动词ing18 小时前
【题目练习】动态规划+背包问题
数据结构·目标检测
杜 硕18 小时前
单链表经典算法题
数据结构·算法