046二叉树展开为链表

二叉树展开为链表

题目链接:https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/description/?envType=study-plan-v2\&envId=top-100-liked

我的解答:

复制代码
List<TreeNode> list = new ArrayList<>();
public void flatten(TreeNode root) {
    if(root == null){
        return;
    }
    getList(root);
    for(int i=1; i<list.size(); i++){
        list.get(i-1).left = null;
        list.get(i-1).right = list.get(i);
    }
}
public void getList(TreeNode node){
    if(node == null){
        return;
    }
    list.add(node);
    getList(node.left);
    getList(node.right);
}

分析:代码的时间复杂度为O(n),空间复杂度为O(n)。自己未能想出时间复杂度为O(n)且空间复杂度为O(1)的解法。解题思路:用递归对二叉树进行前序遍历,用集合存储二叉树先序遍历的结果,然后遍历集合更改指针关系即可。

看了官方题解后的解答:

复制代码
//方法一:前序遍历(递归版)(与我的解答一致)
//时间复杂度:O(n)
//空间复杂度:O(n)

//方法一:前序遍历(迭代版)
//时间复杂度:O(n)
//空间复杂度:O(n)
public void flatten(TreeNode root) {
    Deque<TreeNode> stack = new LinkedList<>();
    List<TreeNode> list = new ArrayList<>();
    TreeNode node = root;
    while(node != null || !stack.isEmpty()){
        while(node != null){
            list.add(node);
            stack.push(node);
            node = node.left;
        }
        node = stack.pop().right;
    }
    for(int i = 1; i < list.size(); i++){
        list.get(i-1).right = list.get(i);
        list.get(i-1).left = null;
    }
}

//方法二(只看思路自己实现版):前序遍历和展开同步进行
//时间复杂度:O(n)
//空间复杂度:O(n)
public void flatten(TreeNode root) {
    if(root == null){
        return;
    }
    Deque<TreeNode> stack = new LinkedList<>();
    TreeNode cur = root, pre = null;
    while(cur != null || !stack.isEmpty()){
        while(cur != null){
            if(cur.right != null){
                stack.push(cur.right);
            }
            if(pre != null){
                pre.right = cur;
                pre.left = null;
            }
            pre = cur;
            cur = cur.left;
        }
        if(!stack.isEmpty()){
            cur = stack.pop();
        }
    }
}

//方法二(看了官方实现版,优于只看思路自己实现版):前序遍历和展开同步进行
//时间复杂度:O(n)
//空间复杂度:O(n)
public void flatten(TreeNode root) {
    if(root == null){
        return;
    }
    Deque<TreeNode> stack = new LinkedList<>();
    TreeNode pre = null, cur;
    stack.push(root);
    while(!stack.isEmpty()){
        cur = stack.pop();
        if(pre != null){
            pre.right = cur;
            pre.left = null;
        }
        if(cur.right != null){
            stack.push(cur.right);
        }
        if(cur.left != null){
            stack.push(cur.left);
        }
        pre = cur;
    }
}

//方法三:寻找前驱节点
//时间复杂度:O(n)
//空间复杂度:O(1)
public void flatten(TreeNode root) {
    TreeNode cur = root, right;
    while(cur != null){
        if(cur.left != null){
            TreeNode temp = cur.left;
            while(temp.right != null){
                temp = temp.right;
            }
            temp.right = cur.right;
            cur.right = cur.left;
            cur.left = null;
        }
        cur = cur.right;
    }
}

分析:

​ 1、方法一和方法二都采用二叉树的前序遍历方法,区别在于,方法一是将前序遍历的结果存入集合中,遍历完后再遍历集合更改指针关系;而方法二利用栈保存了每个节点的右孩子信息,每次右孩子先入栈,左孩子后入栈,且用pre保存当前已经展开的链表尾节点,每次出栈的同时更改pre的指针关系。重复以上操作直到栈为空。

​ 2、方法三的解题思路:遍历到当前节点时分为两种情况------若当前节点左孩子为空,则无需做任何改变;若当前节点左孩子不为空,根据前序遍历的顺序关系,每次找到当前节点的左子树前序遍历的最后一个节点(最右节点),将当前节点的右子树连接到最右节点,然后让当前节点的左孩子成为右孩子,并让左孩子为空,最后继续遍历下一个节点。重复以上操作直到当前节点为空。

总结

  • 本题主要是需要掌握二叉树的前序遍历的流程和特点。
相关推荐
8Qi816 小时前
LeetCode 235. 二叉搜索树的最近公共祖先(LCA)
算法·leetcode·二叉树·递归·二叉搜索树·lca·迭代
sugar__salt16 小时前
从栈队列数据结构到JS原型面向对象全解
前端·javascript·数据结构
8Qi818 小时前
LeetCode 494:目标和(Target Sum)—— 题解 ✅
算法·leetcode·职场和发展·动态规划·01背包
froyoisle19 小时前
CSP-J 历年复赛 T1 及解析(2019~2025)
数据结构·c++·算法·csp-j·csp·算法竞赛·信息学
喜欢打篮球的普通人19 小时前
LLVM 后端流程与关键数据结构:从 IR 到机器码的入门笔记
java·数据结构·笔记
Misnearch20 小时前
1、数组/字符串
java·数据结构·算法
008爬虫实战录20 小时前
【数据结构】 树、二叉树、完全二叉树,先序遍历、中序遍历、后序遍历
数据结构·算法
AllData公司负责人20 小时前
大模型赋能AllData数据中台,系列升级|通过联合智谱大模型与BiSheng开源项目,建设企业大模型应用开发平台,支持知识库向量检索!
大数据·数据结构·数据库·算法·大模型·向量数据库·智谱ai
这料鬼有毒20 小时前
二刷hot100-78.子集
算法·leetcode·职场和发展
梦想的颜色1 天前
MySQL 数据存储结构与查询执行生命周期深度解析
运维·数据结构·数据库·mysql·线程·优化