zoukankan      html  css  js  c++  java
  • LeetCode---二叉树3-总结例题

    二叉树-总结例题

    1-从中序与后序遍历序列构造二叉树

    给定二叉树的后序遍历和二叉树的中序遍历
    想法:

    1. 先根据后序遍历的最后一个元素构造根节点
    2. 寻找根节点在中序遍历中的位置
    3. 递归构建根节点的左右子树
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
            if(inorder.size() == 0 || postorder.size() == 0)
                return NULL;
            int _is = 0;
            int _ie = inorder.size()-1;
            int _ps = 0;
            int _pe = postorder.size()-1;
            return build(inorder,postorder,_is,_ie,_ps,_pe);
    
        }
        // 构建节点的递归函数     
        TreeNode* build(vector<int>& inorder, vector<int>& postorder,int is,int ie,int ps,int pe)
        {
            // 构建根节点
            TreeNode* ans = new TreeNode(postorder[pe]);
            int ll = 0;
            int rl = 0;
            for(int i = is ; i <= ie ; ++i )
            {
                if(inorder[i] == postorder[pe])
                {
                    // 左子树长度
                    ll = i - is;
                    // 右子树长度
                    rl = ie - i;
                }
            }
            // 构建左子树
            if ( ll > 0 )
            {
                ans->left = build(inorder,postorder,is,is+ll-1,ps,ps+ll-1); 
            }
            // 构建右子树
            if ( rl > 0 )
            {
                ans->right = build(inorder,postorder,ie-rl+1,ie,pe-rl,pe-1);
            }
            return ans;
        }
    };
    

    总结:

    1. 返回类型为pointer,异常情况可以直接返回NULL
    2. 上面的代码里用了两个变量,ll和rl分别表示,左右子树在vector里面的长度。
    3. 每次调用递归函数,都用ll和rl改变两个容器的首尾下标。

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

    想法:

    1. 先根据先序遍历的最后一个元素构造根节点
    2. 寻找根节点在中序遍历中的位置
    3. 递归构建根节点的左右子树
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
            return build(inorder,preorder,0,inorder.size()-1,0,preorder.size()-1);
        }
        TreeNode* build(vector<int>& inorder,vector<int>& preorder, int is,int ie,int ps,int pe) 
        {
            if(inorder.size()==0 || preorder.size()==0)
            {
                return NULL;
            }
            int ll = 0 ; 
            int rl = 0 ; 
            TreeNode* ans = new TreeNode(preorder[ps]);
            for(int i = is; i<= ie; i++)
            {
                if(preorder[ps]==inorder[i])
                {
                    ll = i - is ;
                    rl = ie - i;
                }
            }
            if ( ll > 0 )
            {
                ans->left = build (inorder,preorder,is,is+ll-1,ps+1 ,ps+ll );
            }
            if ( rl > 0 )
            {
                ans->right = build(inorder,preorder,ie-rl+1,ie,pe-rl+1,pe);
            }
            return ans;
        }
    };
    

    3-填充每个节点的下一个右侧节点指针(完美二叉树)

    想法:

    1. 通过层次遍历,使用队列
    2. 每一层的最后一个节点指向next,否则就指向下一个
    class Solution {
    public:
        Node* connect(Node* root) {
            if( root == NULL)
                return NULL;
            queue<Node*> q;
            q.push(root);
            // 记录每一层的元素个数
            while( ! q.empty())
            {
                int num = q.size();
                // 遍历当前层(队列)里面的每个元素
                for(int i = 0; i < num; i++)
                {
                    // p指向 是队列的头节点
                    Node* p = q.front();
                    // 出队
                    q.pop();
                    // 如果到当前层最后一个元素了,next指针指向NULL,队未空,next指向队头节点
                    if(i == num-1)
                        p->next = NULL;
                    else
                        p->next = q.front();
                    // p 的左右孩子节点入队
                    if( p->left != NULL )
                        q.push( p->left );
                    if ( p->right != NULL )
                        q.push( p->right );
                }
            }
            return root;
        }
    };
    

    4-填充每个节点的下一个右侧节点指针(非完美二叉树)

    我的解法同上。

    class Solution {
    public:
        Node* connect(Node* root) {
            if( root == NULL)
                return NULL;
            queue<Node*> q;
            q.push(root);
            // 记录每一层的元素个数
            while( ! q.empty())
            {
                int num = q.size();
                // 遍历当前层(队列)里面的每个元素
                for(int i = 0; i < num; i++)
                {
                    // p指向 是队列的头节点
                    Node* p = q.front();
                    // 出队
                    q.pop();
                    // 如果到当前层最后一个元素了,next指针指向NULL,队未空,next指向队头节点
                    if(i == num-1)
                        p->next = NULL;
                    else
                        p->next = q.front();
                    // p 的左右孩子节点入队
                    if( p->left != NULL )
                        q.push( p->left );
                    if ( p->right != NULL )
                        q.push( p->right );
                }
            }
            return root;
        }
    };
    

    5-二叉树的最近公共祖先

    自己的想法 :

    1. 在树中分别查找目标节点。把查找的路径存放到两个栈里。
    2. 其中一个栈依次出栈,在另个栈里查找这个出栈的节点。
    3. Note:因为搜索到的路径是唯一的。
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
            stack<TreeNode*> A;
            stack<TreeNode*> B;
            find(root,p,A);
            find(root,q,B);
            
            vector<int> bb;
            for(int i = 0; i< B.size();++i)
            {
                bb.push_back(B.top()->val);
                B.pop();
            }
            while(!A.empty())
            {
                TreeNode* ans = A.top();
                for(int i = 0 ; i< bb.size();++i)
                {
                    if( ans->val == bb[i])
                        return ans;
                }
            }
            return NULL;
        }
        void find (TreeNode* root ,TreeNode* target, stack<TreeNode*> &ss)
        {
            if (! root)
                return ;
            if(root->val == target->val)
            {
                ss.push(root);
            }
            if(root->left != NULL)
            {
                vector<int> lv = dfs(root->left);
                for(int i = 0; i < lv.size() ; ++i )
                {
                    if(lv[i] == target->val)
                    {
                        ss.push(root->left);
                        find(root->left,target ,ss);
                    }
                }
            }
            if(root->right != NULL)
            {
                vector<int> rv = dfs(root->right);
                for(int i = 0; i < rv.size() ; ++i )
                {
                    if(rv[i] == target->val)
                    {
                        ss.push(root->right);
                        find(root->right,target,ss);
                    }
                }
            }   
        }
        
        vector<int> dfs(TreeNode* root)
        {
            vector<int> order;
            helper(root,order);
            return order;
        }
        void helper( TreeNode* root, vector<int>& vv)
        {
            if(root->left!=NULL)
                helper(root->left,vv);
            vv.push_back(root->val);
            if(root->right != NULL)
                helper(root->right,vv);
        }
    };
    
    代码超出时间限制

    看看人家的代码吧:

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
            if(!root || !p || !q)
                return NULL;
            vector<TreeNode*> A;
            vector<TreeNode*> B;
            dfs(root,p,A);
            dfs(root,q,B);
            
            TreeNode* ans ;
            int len = min(A.size(),B.size());
            for(int i = 0; i < len ; i++)
            {
                if(A[i]->val != B[i]->val)
                    break;
                ans = A[i];
            }
            return ans;
    
        }
        bool dfs(TreeNode* root,TreeNode* target,vector<TreeNode*>& path)
        {
            if( root == target ){
                path.push_back(root);
                return true;
            }
            path.push_back(root);
            if( root->left && dfs( root->left , target,path ))
                return true;
            if(root->right && dfs( root->right , target , path ))
                return true;
            // 回溯???
            path.pop_back();
            return false;
        }
        
    };
    

    问题:

    1. 在深度遍历函数里,pop_back()的理解:回溯???
    2. for循环的问题
            for(int i = 0; i < len ; i++)
            {
                if(A[i]->val != B[i]->val)
                    break;
                ans = A[i];
            }
    
    干啥啥不行,吃饭第一名
  • 相关阅读:
    IsEmpty函数和IsNull函数之间的区别
    JavaScript的self和this使用小结
    PHP中读写文件实现代码
    ExtJs的数据代理proxy
    php递归列出所有文件和目录的代码
    解析Extjs与php数据交互(增删查改)
    MySql 批量创建、导入实例
    MySQL 进入 导入
    小知识:批量导入数据
    js 扩展实例
  • 原文地址:https://www.cnblogs.com/jiangxinyu1/p/12284995.html
Copyright © 2011-2022 走看看