leetcode-105 从前序与中序遍历序列构造二叉树-使用栈代替递归

这篇博客介绍了如何将递归方法用于从预序和中序遍历构造二叉树的问题,转变为使用栈进行迭代解决。通过分析递归过程中的关键状态,如子树范围、父节点等,定义了栈保存的结构,并展示了两种不同的结构实现。最终给出了两种基于栈的解决方案,实现了从递归到迭代的转换。
摘要由CSDN通过智能技术生成

使用递归法这个是很容易实现的(当然前提是你对二叉树遍历顺序熟悉)
本文重点是采用栈的方式来解决问题, 毕竟据说递归能实现的解法用栈都能实现

步骤一: 观察递归法需要知道的状态

一般常见写法

这个写法可能没那么好观察出状态

class Solution {
public:
    TreeNode* buildTreeHelper(vector<int>& preorder, int l1, int h1, vector<int>& inorder, int l2, int h2) {
        if (l1 > h1) {
            return nullptr;
        }
        int val = preorder[l1];
        int i = l2;
        for (; i <= h2; i++) {
            if (inorder[i] == val) {
                break;
            }
        }
        int lsz = i - l2;
        auto root = new TreeNode(val);
        root->left = buildTreeHelper(preorder, l1 + 1, l1 + lsz, inorder, l2, i - 1);
        root->right= buildTreeHelper(preorder, l1 + lsz + 1, h1, inorder, i + 1, h2);
        return root;
    }

    // 最一般的递归构造
    TreeNode* buildTree_recursion(vector<int>& preorder, vector<int>& inorder) {
        return buildTreeHelper(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size() - 1);
    }
}

那么如果换成下面的写法

   void buildTreeHelper(vector<int>& preorder, int l1, int h1, vector<int>& inorder, int l2, int h2, TreeNode* &father, TreeNode* TreeNode::*child) {
        if (l1 > h1) {
            return;
        }
        int val = preorder[l1];
        auto node = new TreeNode(val);
        if (nullptr == father) {
            father = node;
        } else {
            father->*child = node;
        }
        int i = l2;
        for (; i <= h2; i++) {
            if (inorder[i] == val) {
                break;
            }
        }
        int lsz = i - l2;
        buildTreeHelper(preorder, l1 + 1, l1 + lsz, inorder, l2, i - 1, node, &TreeNode::left);
        buildTreeHelper(preorder, l1 + lsz + 1, h1, inorder, i + 1, h2, node, &TreeNode::right);
    }

    // 最一般的递归构造
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        TreeNode* root = nullptr;
        buildTreeHelper2(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size() - 1, root, nullptr);
        return root;
    }

知道栈必须保存的状态

1. preorder 全局可以获取
2. l1
3. h1
4. inorder 全局可以获取
4. l2
5. h2
6. father
7. child 或者用tag代替

定义栈保存结构

可用结构一

  struct OneItemTag {
        int l1, h1, l2, h2;
        int tag;
        TreeNode* father;
        OneItemTag(int l1, int h1, int l2, int h2, int tag, TreeNode* fa = nullptr):l1(l1), h1(h1), l2(l2), h2(h2), tag(tag), father(fa){}
    };

可用结构二

  struct OneItem {
        int l1, h1, l2, h2;
        TreeNode* TreeNode::*child;
        TreeNode* father;
        OneItem(int l1, int h1, int l2, int h2, TreeNode* TreeNode:: *child, TreeNode* fa = nullptr):l1(l1), h1(h1), l2(l2), h2(h2), child(child), father(fa){}
    };

逻辑处理

/*
 * @lc app=leetcode.cn id=105 lang=cpp
 *
 * [105] 从前序与中序遍历序列构造二叉树
 */

// @lc code=start
/**
 * 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:
    TreeNode* buildTreeHelper(vector<int>& preorder, int l1, int h1, vector<int>& inorder, int l2, int h2) {
        if (l1 > h1) {
            return nullptr;
        }
        int val = preorder[l1];
        int i = l2;
        for (; i <= h2; i++) {
            if (inorder[i] == val) {
                break;
            }
        }
        int lsz = i - l2;
        auto root = new TreeNode(val);
        root->left = buildTreeHelper(preorder, l1 + 1, l1 + lsz, inorder, l2, i - 1);
        root->right= buildTreeHelper(preorder, l1 + lsz + 1, h1, inorder, i + 1, h2);
        return root;
    }

    // 最一般的递归构造
    TreeNode* buildTree_recursion(vector<int>& preorder, vector<int>& inorder) {
        return buildTreeHelper(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size() - 1);
    }

    struct OneItemTag {
        int l1, h1, l2, h2;
        int tag;
        TreeNode* father;
        OneItemTag(int l1, int h1, int l2, int h2, int tag, TreeNode* fa = nullptr):l1(l1), h1(h1), l2(l2), h2(h2), tag(tag), father(fa){}
    };

    TreeNode* buildTreeTag(vector<int>& preorder, vector<int>& inorder) {
        if (preorder.empty()) {
            return nullptr;
        }
        stack<OneItemTag> st;
        TreeNode* root = nullptr;
        st.push(OneItemTag(0, (int)preorder.size() - 1, 0, (int)inorder.size() - 1, 0, nullptr));

        while (!st.empty()) {
            auto one = st.top();
            st.pop();
            int l1 = one.l1;
            int h1 = one.h1;
            int l2 = one.l2;
            int h2 = one.h2;

            int tag = one.tag;
            TreeNode* father = one.father;
            if (l1 > h1) {
                continue;
            }
            if (l1 == h1) {
                auto node = new TreeNode(preorder[l1]);
                if (father == nullptr) {
                    root = node;
                } else {
                    if (-1 == tag) {
                        father->left = node;
                    } else if (1 == tag) {
                        father->right = node;
                    }
                }
                continue;
            }
            int val = preorder[l1];
            int i = l2;
            for (; i <= h2; i++) {
                if (inorder[i] == val) {
                    break;
                }
            }
            int lsz = i - l2;
            auto node = new TreeNode(val);
            if (father == nullptr) {
                root = node;
            } else {
                if (-1 == tag) {
                    father->left = node;
                } else if (1 == tag) {
                    father->right = node;
                }
            }
            st.push(OneItemTag(l1 + 1, l1 + lsz, l2, i - 1, -1, node));
            st.push(OneItemTag(l1 + lsz + 1, h1, i + 1, h2, 1, node));
        }
        return root;
    }

    struct OneItem {
        int l1, h1, l2, h2;
        TreeNode* TreeNode::*child;
        TreeNode* father;
        OneItem(int l1, int h1, int l2, int h2, TreeNode* TreeNode:: *child, TreeNode* fa = nullptr):l1(l1), h1(h1), l2(l2), h2(h2), child(child), father(fa){}
    };
    // 递归的都能用栈, 用栈场所
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if (preorder.empty()) {
            return nullptr;
        }
        stack<OneItem> st;
        TreeNode* root = nullptr;
        st.push(OneItem(0, (int)preorder.size() - 1, 0, (int)inorder.size() - 1, nullptr, nullptr));
        while (!st.empty()) {
            auto one = st.top();
            st.pop();
            int l1 = one.l1;
            int h1 = one.h1;
            int l2 = one.l2;
            int h2 = one.h2;
            auto child = one.child;
            TreeNode* father = one.father;
            if (l1 > h1) {
                continue;
            }
            if (l1 == h1) {
                auto node = new TreeNode(preorder[l1]);
                if (father == nullptr) {
                    root = node;
                } else {
                    father->*child = node;
                }
                continue;
            }
            int val = preorder[l1];
            int i = l2;
            for (; i <= h2; i++) {
                if (inorder[i] == val) {
                    break;
                }
            }
            int lsz = i - l2;
            auto node = new TreeNode(val);
            if (father == nullptr) {
                root = node;
            } else {
                father->*child = node;
            }
            st.push(OneItem(l1 + 1, l1 + lsz, l2, i - 1, &TreeNode::left, node));
            st.push(OneItem(l1 + lsz + 1, h1, i + 1, h2, &TreeNode::right, node));
        }
        return root;
    }
};
// @lc code=end

leetcode-105 从前序与中序遍历序列构造二叉树
leetcode-105 从前序与中序遍历序列构造二叉树
leetcode-105 从前序与中序遍历序列构造二叉树
leetcode-105 从前序与中序遍历序列构造二叉树
leetcode-105 从前序与中序遍历序列构造二叉树
leetcode-105 从前序与中序遍历序列构造二叉树
leetcode-105 从前序与中序遍历序列构造二叉树
leetcode-105 从前序与中序遍历序列构造二叉树
leetcode-105 从前序与中序遍历序列构造二叉树
leetcode-105 从前序与中序遍历序列构造二叉树
leetcode-105 从前序与中序遍历序列构造二叉树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值