挑战刷leetcode第12天(二叉树转换成链表)

144 阅读4分钟

哪吒、敖丙和申公豹的二叉树扁平化大作战:递归与迭代的终极对决

大家好,我是哪吒!今天不闹海,也不打妖怪,咱们来聊聊二叉树的扁平化。你没听错,就是那个让你头大的二叉树!最近我在《哪吒2》里和敖丙、申公豹一起研究了这个难题,今天就来给大家分享一下我们的“战斗”过程。


什么是二叉树扁平化?

简单来说,就是把一棵二叉树变成一个链表,而且这个链表还是按照前序遍历的顺序排列的。听起来是不是有点像把一棵树“拍扁”成一条线?没错,就是这么回事!就像我哪吒的风火轮,把复杂的树结构碾成一条直线!


第一回合:递归 vs 迭代

递归:哪吒的“分身术”

递归就像我的分身术,自己调用自己,直到完成任务。敖丙看了直呼:“这也太神奇了吧!”我们先用Java和C++来实现一下。

Java代码:

public void flatten(TreeNode root) {
    List<TreeNode> list = new ArrayList<>();
    preIterator(list, root);
    if (list.size() != 0 && list.size() >= 1) {
        for (int i = 1; i < list.size(); i++) {
            TreeNode pre = list.get(i - 1);
            TreeNode next = list.get(i);
            pre.left = null;
            pre.right = next;
        }
    }
}

public void preIterator(List<TreeNode> list, TreeNode root) {
    if (root == null) {
        return;
    }
    list.add(root);
    preIterator(list, root.left);  // 分身术:左子树
    preIterator(list, root.right); // 分身术:右子树
}

C++代码:

void flatten(TreeNode* root) {
    vector<TreeNode*> vector;
    preIterator(vector, root);
    if (vector.size() <= 1) {
        return;
    }
    for (int i = 1; i < vector.size(); i++) {
        TreeNode* pre = vector.at(i - 1);
        TreeNode* next = vector.at(i);
        pre->left = nullptr;
        pre->right = next;
    }
}

void preIterator(vector<TreeNode*>& vector, TreeNode* root) {
    if (root == nullptr) {
        return;
    }
    vector.push_back(root);
    preIterator(vector, root->left);  // 分身术:左子树
    preIterator(vector, root->right); // 分身术:右子树
}

敖丙看完代码后,感叹道:“这递归真是妙啊!就像你的分身术,一层一层地解决问题。”我得意地笑了笑:“那当然,这可是我的看家本领!”


迭代:申公豹的“风火轮计划”

申公豹听了不服气,跳出来说:“哼,递归算什么!我的迭代才是真正的‘风火轮计划’,一步一个脚印,稳扎稳打!”于是,他掏出了迭代的代码。

Java代码:

public void flatten(TreeNode root) {
    if (root == null) {
        return;
    }
    Stack<TreeNode> stack = new Stack<>();
    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();
        node = node.right; // 再往右冲
    }
    if (list.size() <= 1) {
        return;
    }
    for (int i = 1; i < list.size(); i++) {
        TreeNode pre = list.get(i - 1);
        TreeNode next = list.get(i);
        pre.left = null;
        pre.right = next;
    }
}

C++代码:

void flatten(TreeNode* root) {
    if (root == nullptr) {
        return;
    }
    stack<TreeNode*> stack;
    vector<TreeNode*> list;

    TreeNode* node = root;
    while (node != nullptr || !stack.empty()) {
        while (node != nullptr) {
            list.push_back(node);
            stack.push(node);
            node = node->left;  // 先往左冲
        }
        node = stack.top();
        stack.pop();
        node = node->right; // 再往右冲
    }
    if (list.size() <= 1) {
        return;
    }
    for (int i = 1; i < list.size(); i++) {
        TreeNode* pre = list.at(i - 1);
        TreeNode* next = list.at(i);
        pre->left = nullptr;
        pre->right = next;
    }
}

申公豹得意地说:“看到没?我的迭代就像风火轮,一步一步往前滚,稳得不行!”敖丙点点头:“确实,迭代虽然代码长点,但不容易栈溢出,适合大规模战斗。”


第二回合:递归 vs 迭代,谁更胜一筹?

哪吒(我):“递归代码简洁,但可能会遇到栈溢出的问题,就像我的分身术,分身太多也会累趴下。”

敖丙:“迭代代码稍显复杂,但更节省内存,就像申公豹的风火轮,虽然慢点,但稳扎稳打。”

申公豹:“哼,你们俩别争了!递归和迭代各有千秋,关键看场景。就像我们三个,各有各的本事,合作才能无敌!”


坚持的意义

无论是递归还是迭代,解决问题的关键在于坚持。就像我在《哪吒2》里一样,面对困难不退缩,最终总能找到解决的办法。敖丙和申公豹也深有感触:“编程如修行,坚持才能突破自我!”


总结

今天,我们通过哪吒、敖丙和申公豹的视角,学习了二叉树的扁平化。递归像哪吒的分身术,简洁但可能栈溢出;迭代像申公豹的风火轮,稳扎稳打但代码稍长。无论选择哪种方法,坚持才是最重要的!

哪吒的口号:我命由我不由天,代码由我不由Bug!
敖丙的口号:稳扎稳打,步步为营!
申公豹的口号:风火轮计划,一步一个脚印!

好了,今天的分享就到这里。如果你觉得这篇文章对你有帮助,别忘了点赞、分享哦!我们下次再见!


作者:哪吒、敖丙、申公豹
合作宣言:编程如修行,合作才能无敌!