lotus

贵有恒何必三更眠五更起 最无益只怕一日曝十日寒

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

1. 题目

 

 考察点

这道题的考察点是二叉树的遍历和展平,

需要掌握前序遍历,中序遍历和后序遍历的顺序和方法,以及如何将二叉树转换为链表的技巧。

这道题可以用递归,迭代或者原地修改的方式来解决,需要注意展平后的链表要保持和二叉树的前序遍历相同的顺序。

这道题也可以扩展为按照中序遍历或者后序遍历的顺序来展平,需要改变一些细节。

2. 解法

有两种解法

  • 递归 
  • 迭代

解法一:递归 

思路

好的,我可以条理的讲一下递归代码的逻辑。这个递归的思路是这样的:

  • 首先,如果根节点为空,或者根节点没有左右子节点,那么直接返回根节点,不需要展平。
  • 然后,分别对左右子树进行递归展平,得到两个链表。
  • 接着,将左子树的链表接到根节点的右子节点上,将原来的右子树的链表接到左子树的链表的末尾。
  • 最后,将根节点的左子节点置为空,返回根节点作为整个链表的头节点。

代码逻辑

 

具体实现

// 定义一个二叉树节点的类
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 || (root.left == null && root.right == null)) {
            return;
        }
        
        // 分别对左右子树进行递归展平,得到两个链表
        flatten(root.left);
        flatten(root.right);
        
        // 将左子树的链表接到根节点的右子节点上,将原来的右子树的链表接到左子树的链表的末尾
        TreeNode temp = root.right; // 保存原来的右子树
        root.right = root.left; // 将展平的左子树移到右边
        root.left = null; // 将左子节点置为空
        
        // 找到展平的左子树的末尾,然后将原来的右子树接上去
        TreeNode curr = root;
        while (curr.right != null) {
            curr = curr.right;
        }
        curr.right = temp; // 追加原来的右子树
        
        // 返回展平后的根节点
        return;
    }
}

  

解法二:迭代

思路

好的,我可以再讲一下迭代的代码逻辑。这个迭代的思路是这样的:

  • 首先,创建一个栈来存储右子树,初始化当前节点为根节点。
  • 然后,循环直到当前节点为空且栈为空。
  • 在循环中,如果当前节点有右子节点,将它压入栈中;如果当前节点有左子节点,将它移到右边,然后将左边置为空;否则,从栈中弹出一个右子树,将它移到右边;最后,移动到链表中的下一个节点。
  • 最后,返回展平后的根节点。

 

具体实现

// 定义一个二叉树节点的类
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<>();
        
        // 初始化当前节点为根节点
        TreeNode curr = root;
        
        // 循环直到当前节点为空且栈为空
        while (curr != null || !stack.isEmpty()) {
            // 如果当前节点有右子节点,将它压入栈中
            if (curr.right != null) {
                stack.push(curr.right);
            }
            
            // 如果当前节点有左子节点,将它移到右边,然后将左边置为空
            if (curr.left != null) {
                curr.right = curr.left;
                curr.left = null;
            } else { // 否则,从栈中弹出一个右子树,将它移到右边
                curr.right = stack.pop();
            }
            
            // 移动到链表中的下一个节点
            curr = curr.right;
        }
        
        // 返回展平后的根节点
        return;
    }
}

  

3. 总结

posted on 2023-04-25 13:54  白露~  阅读(7)  评论(0编辑  收藏  举报