zoukankan      html  css  js  c++  java
  • leetcode在线编程【树专题】

    二叉树的最小深度
    递归遍历每个节点并计数深度,遍历到叶子节点时更新最小深度,并返回,非叶子节点取返回值的最小深度返回

    class Solution {
    public:
        int ans=9999999;
        int dfs(TreeNode *root,int dep)
        {
            dep++;
            if(root->left==NULL&&root->right==NULL)return min(ans,dep);
            int ldep=ans,rdep=ans;
            if(root->right)rdep=dfs(root->right,dep);
            if(root->left)ldep=dfs(root->left,dep);
            return min(ldep,rdep);
            
        }
        int run(TreeNode *root) {
            if(root==NULL)return 0;
            return dfs(root,0);
        }
    };
    

    二叉树的后序遍历(非递归)
    用栈实现,基本上就是模拟输出的过程。首先放入根节点,最外层循环保证整棵树的正常输出,第一个内层循环用于模拟递归左孩子,即只要有左孩子就一直往栈里塞。 第二个内层循环模拟右孩子插入和递归回溯到根节点的过程。当回溯出栈时,判断栈顶是否与上一个输出的节点有父子关系【此处需要一个标记记录,即代码中lastnode】,若上一个输出节点是当前栈顶右孩子,说明回溯到了某个根节点,直接出栈。亦或是当栈顶元素没有右孩子时,那也该轮到当前栈顶输出了。若两种情况都不属于那就是该遍历右孩子了,直接右孩子进栈,并且退出第二个内层循环,因为此时遇到了一个新子树,按照顺序应模拟递归遍历左孩子的过程。

    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<int> postorderTraversal(TreeNode *root) {
            vector<int>ans;
            stack<TreeNode*>q;
            if(root==NULL)return ans;
            TreeNode *rt=root;
            q.push(rt);
            TreeNode *lastnode=NULL;
            while(!q.empty())
            {
                while(q.top()->left)q.push(q.top()->left);
                while(!q.empty())
                {
                    if(lastnode==q.top()->right||q.top()->right==NULL)
                    {
                        ans.push_back(q.top()->val);
                        lastnode=q.top();
                        q.pop();
                    }
                    else if(q.top()->right!=NULL)
                    {
                        q.push(q.top()->right);
                        break;
                    }
                }
            }
            return ans;
        }
    };
    

    前序遍历二叉树(非递归)
    这个要比后序遍历简单得多,直接模拟根节点进栈,出栈输出时将右孩子入栈,再把左孩子入栈。因为栈的顺序是先进后出。跑一层循环即可。

    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<int> preorderTraversal(TreeNode *root) {
            vector<int>ans;
            if(root==NULL)return ans;
            stack<TreeNode *>q;
            q.push(root);
            while(!q.empty())
            {
                TreeNode *tmp=q.top();
                q.pop();
                ans.push_back(tmp->val);
                if(tmp->right)q.push(tmp->right);
                if(tmp->left)q.push(tmp->left);
            }
            return ans;
        }
    };
    

    Given a binary tree containing digits from0-9only, each root-to-leaf path could represent a number.
    An example is the root-to-leaf path1->2->3which represents the number123.
    Find the total sum of all root-to-leaf numbers.
    For example,

        1
       / 
      2   3
    

    The root-to-leaf path1->2represents the number12.
    The root-to-leaf path1->3represents the number13.

    Return the sum = 12 + 13 =25.
    输入一棵树,每个节点是一个一位数,一条路径的数是一个十进制数,输出所有路径的十进制数求和结果

    递归遍历,每次 ×10+val得到十进制数,叶子节点对ans求和即可。其实就是一个裸的遍历树过程。

    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        int ans=0;
        void dfs(TreeNode *rt,int sum)
        {
            sum=sum*10+rt->val;
            if(rt->left==NULL&&rt->right==NULL)
            {
                ans+=sum;
                return ;
            }
            else 
            {
                if(rt->left!=NULL)dfs(rt->left,sum);
                if(rt->right!=NULL)dfs(rt->right,sum);
            }
            return ;
        }
        int sumNumbers(TreeNode *root) {
            TreeNode *tmp=root;
            if(tmp!=NULL)dfs(tmp,0);
            return ans;
        }
    };
    

    Given a binary tree, find the maximum path sum.
    The path may start and end at any node in the tree.
    For example:
    Given the below binary tree,

           1
          / 
         2   3
    

    Return6.
    输出该树最大路径和
    节点值存在负数,因此结果初始化是负数最大值。
    递归遍历,叶子节点返回当前值大小。
    非叶子节点计算,若某一条路径经过当前结点的时的路径最大和,并更新ans,而其左右两子树回溯的是经过子节点的最大和。设想,若当前节点作为最大路径和的一部分,那么肯定选择左子树中的最大和或右子树的最大和,即max(leftsum,rightsum),以此回溯给父节点让其继续做筛选和判断。回溯的过程只提供子树最大和,用于给父节点搜集两段路径最大和,然后合并成为完整的路径和,并更新ans。
    需要注意的是,因为存在负数,并且最大路径和的路径并不一定必须到大叶子节点,那么就有些负数节点的取舍问题。这就像树上的最大子段和。其实并没有那么复杂,最大子段和的DP算法是当求和小于0时舍去之前的结果,并初始化结果为0,那么此处也是,当左右子链的最大和甚至比只取当前结点的值还小时,那么只返回当前节点的值,这样就直接舍去了损耗求和的负数节点。

    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        int ans=-999999;
        int dfs(TreeNode *rt)
        {
            if(rt->left==NULL&&rt->right==NULL) return rt->val;
            else 
            {
                int lsum=0,rsum=0;
                if(rt->left!=NULL) lsum=dfs(rt->left),ans=ans<lsum?lsum:ans;
                if(rt->right!=NULL) rsum=dfs(rt->right),ans=ans<rsum?rsum:ans;
                int tmp=lsum+rt->val+rsum;
                if(tmp>ans) ans=tmp;
                if(rt->val>ans) ans=rt->val;
                return max(rt->val+max(lsum,rsum),rt->val);
            }
        }
        int maxPathSum(TreeNode *root) {
            int tmp=dfs(root);
            if(ans<tmp)ans=tmp;
            return ans;
        }
    };
    

    Follow up for problem “Populating Next Right Pointers in Each Node”.
    What if the given tree could be any binary tree? Would your previous solution still work?
    Note:
    You may only use constant extra space.
    For example,
    Given the following binary tree,

             1
           /  
          2    3
         /     
        4   5    7
    

    After calling your function, the tree should look like:

             1 -> NULL
           /  
          2 -> 3 -> NULL
         /     
        4-> 5 -> 7 -> NULL
    

    给二叉树的每层加上指针变成链表
    首先这是一个层序遍历,然后为了区分每个节点是哪一层的,可以这样处理,之前不区分的广搜是while内直接对队首节点顺序遍历,在将子节点投入队列。此处可以用一个for循环将队列内现有值全部弹出,然后加上指针组成链表,顺便将其子节点插入队列。很明显因为每次弹出队列的都是一整层节点,放入队列的也是下一层节点,不会出现串层的情况,以此区分每个节点属于哪一层。

    /**
     * Definition for binary tree with next pointer.
     * struct TreeLinkNode {
     *  int val;
     *  TreeLinkNode *left, *right, *next;
     *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
     * };
     */
    class Solution {
    public:
        void connect(TreeLinkNode *root) {
            if(root==NULL)return;
            queue<TreeLinkNode*>q;
            q.push(root);
            while(!q.empty())
            {
                TreeLinkNode *top=q.front();
                int len=q.size();
                q.pop();
                if(top->left)q.push(top->left);
                if(top->right)q.push(top->right);
                for(int i=1;i<len;i++)
                {
                    TreeLinkNode *nxt=q.front();
                    top->next=nxt;
                    top=nxt;
                    q.pop();
                    if(top->left)q.push(top->left);
                    if(top->right)q.push(top->right);
                }
                top->next=NULL;
            }
        }
    };
    

    Given a binary tree and a sum, find all root-to-leaf paths where each path’s sum equals the given sum.
    For example:
    Given the below binary tree andsum = 22,

                  5
                 / 
                4   8
               /   / 
              11  13  4
             /      / 
            7    2  5   1
    

    return

    [
       [5,4,11,2],
       [5,8,4,5]
    ]
    

    给棵树,给个数,输出路径和等于给的数的所有路径
    递归遍历,同时求和,叶子节点时判断路径和是否符合条件,符合条件塞入ans数组中,否则忽略。临时数组记录路径,作为参数递归下去。

    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<vector<int> >ans;
        void dfs(TreeNode *rt,vector<int>tmp,int ts,int sum)
        {
            tmp.push_back(rt->val);
            ts+=rt->val;
            if(rt->left==NULL&&rt->right==NULL)
            {
                if(ts==sum) ans.push_back(tmp);
                return;
            }
            else 
            {
                if(rt->left)dfs(rt->left,tmp,ts,sum);
                if(rt->right)dfs(rt->right,tmp,ts,sum);
            }
        }
        vector<vector<int> > pathSum(TreeNode *root, int sum) {
            if(root==NULL)return ans;
            vector<int>x;
            int ts=0;
            dfs(root,x,ts,sum);
            return ans;
        }
    };
    

    输出树上是否存在某条路径和等于给出的数

    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        int ans=0;
        bool hasPathSum(TreeNode *root, int sum) {
            if(root==NULL)return false;
            if(root->left==NULL&&root->right==NULL)
            {
                ans+=root->val;
                return ans==sum?true:false;
            }
            else
            {
                bool l=false,r=false; 
                ans+=root->val;
                if(root->left) l=hasPathSum(root->left,sum),ans-=root->left->val;
                if(root->right) r=hasPathSum(root->right,sum),ans-=root->right->val;
                return l||r;
            }
        }
    };
    

    Given a binary tree, determine if it is height-balanced.

    For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.
    判断所给树是否是平衡二叉树,不需要判断是否是搜索树
    根据定义平衡二叉树是一 棵空树它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树

    因此递归回溯的过程中返回左右两棵子树的最大深度,若子树的最大深度之差大于1则不符合条件。

    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        bool ans=true;
        int dfs(TreeNode *rt,int dep)
        {
            dep++;
            if(rt->left==NULL&&rt->right==NULL) return dep;
            else
            {
                int depl = dep, depr = dep;
                if(rt->left) depl = dfs(rt->left,dep);
                if(rt->right) depr = dfs(rt->right,dep);
                if(abs(depl-depr)>1) ans=false;
                return max(depl,depr);
            }
        }
        bool isBalanced(TreeNode *root) {
            int dep=0;
            if(root==NULL)return true;;
            dfs(root,dep);
            return ans?true:false;
        }
    };
    

    递归层序遍历,并倒叙输出每层元素
    用到了vector构造函数,其实就是先计算最大深度然后利用每层的递归深度来确定ans的vector中存在第几行。因为树的遍历顺序是普通的前序遍历,每层遍历顺序是层序的。

    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        int dfs(TreeNode *root,int dep)
        {
            if(root==NULL)return dep;
            dep++;
            int l=dep,r=dep;
            if(root->left==NULL&&root->right==NULL)return dep;
            if(root->left)l=dfs(root->left,dep);
            if(root->right)r=dfs(root->right,dep);
            return max(l,r);
        }
        void LOB(vector<vector<int> >&ans,TreeNode *root,int num)
        {
            num--;
            ans[num].push_back(root->val);
            if(root->left==NULL&&root->right==NULL)return ;
            if(root->left)LOB(ans,root->left,num);
            if(root->right)LOB(ans,root->right,num);
        }
        vector<vector<int> > levelOrderBottom(TreeNode *root) {
            int num=dfs(root,0);
            vector<vector<int> >ans(num,vector<int>());
            if(root==NULL)return ans;
            LOB(ans,root,num);
            return ans;
        }
    };
    

    根据后序遍历和中序遍历建树,返回树根节点
    跟取中序遍历和前序遍历恢复树结构/输出后序遍历的题一样,记住阿里面试官跟我说的,层序遍历只需记录每个节点是否有子节点就可以恢复树结构。

    恢复树结构【建树】只是将原题中,当前结点放入ans数组的操作变成return当前节点指针。递归回溯每个节点指针,并赋值左右孩子指针。

    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        int find(vector<int>inorder,int tmp,int l,int r)
        {
            for(int i=l;i<r;i++)
                if(tmp==inorder[i])return i;
            return 0;
        }
        TreeNode *halfpath(vector<int>inorder,vector<int>postorder,int bl,int br,int al,int ar)
        {
            TreeNode *tmp=new TreeNode(postorder[br-1]);
            if(al==ar)return NULL;
            int root = find(inorder,postorder[br-1],al,ar);
            int len=ar-1-root;
            tmp->right=halfpath(inorder,postorder,br-len-1,br-1,root+1,ar);
            tmp->left=halfpath(inorder,postorder,bl,br-len-1,al,root);
            return tmp;
        }
        TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) {
           if(inorder.size()==0)return NULL;
           return halfpath(inorder,postorder,0,inorder.size(),0,inorder.size());
        }
    };
    

    给中序和前序,构造树,方法同上,注意下加减递归范围的边界就好了

    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        int find(vector<int>inorder,int tmp,int l,int r)
        {
            for(int i=l;i<r;i++)
                if(tmp==inorder[i])return i;
            return 0;
        }
        TreeNode *halfpath(vector<int>&preorder,vector<int>&inorder,int bl,int br,int al,int ar)
        {
            TreeNode *tmp=new TreeNode(preorder[bl]);
            if(al==ar)return NULL;
            int root=find(inorder,preorder[bl],al,ar);
            int len=root-al;
            tmp->left=halfpath(preorder,inorder,bl+1,bl+1+len,al,root);
            tmp->right=halfpath(preorder,inorder,bl+1+len,br,root+1,ar);
            return tmp;
        }
        TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) {
            if(preorder.size()==0)return NULL;
            return halfpath(preorder,inorder,0,preorder.size(),0,preorder.size());
        }
    };
    

    Z字形输出树结构
    基本上就是层序遍历的变形,跟层序遍历分层一样放到vector里,偶数层反转即可

    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<vector<int> > zigzagLevelOrder(TreeNode *root) {
            vector<vector<int> >ans;
            if(root==NULL)return ans;
            queue<TreeNode*>q;
            q.push(root);
            int dep=0;
            while(!q.empty())
            {
                dep++;
                vector<int>tmp;
                int len=q.size();
                for(int i=1;i<=len;i++)
                {
                    tmp.push_back(q.front()->val);
                    if(q.front()->left)q.push(q.front()->left);
                    if(q.front()->right)q.push(q.front()->right);
                    q.pop();
                }
                if(!(dep&1))reverse(tmp.begin(),tmp.end());
                ans.push_back(tmp);
            }
            return ans;
        }
    };
    

    判断一棵二叉树是否是镜像二叉树
    Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).

    For example, this binary tree is symmetric:

        1
       / 
      2   2
     /  / 
    3  4 4  3
    

    But the following is not:

        1
       / 
      2   2
          
       3    3
    

    Note:
    Bonus points if you could solve it both recursively and iteratively.

    confused what"{1,#,2,3}"means? > read more on how binary tree is serialized on OJ.

    OJ’s Binary Tree Serialization:
    The serialization of a binary tree follows a level order traversal, where ‘#’ signifies a path terminator where no node exists below.

    Here’s an example:

       1
      / 
     2   3
        /
       4
        
         5
    

    The above binary tree is serialized as"{1,2,3,#,#,4,#,#,5}".

    参数传递两个指针同时遍历移动,并且左指针按照正常前序遍历顺序走动,右指针按照左指针反方向递归移动。随时判断值是否相等即可。最后注意两者同时无孩子时也判定为true

    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        bool dfs(TreeNode *left,TreeNode *right)
        {
            if(left->val==right->val)
            {
                bool l=false,r=false;
                if(left->left&&right->right)l=dfs(left->left,right->right);
                else if(left->left==NULL&&right->right==NULL)l=true;
                if(left->right&&right->left)r=dfs(left->right,right->left);
                else if(left->right==NULL&&right->left==NULL)r=true;
                return l&&r;
            }
            return false;
        }
        bool isSymmetric(TreeNode *root) {
            if(root==NULL)return true;
            if(root->left&&root->right)
                return dfs(root->left,root->right);
            else if(root->left==NULL&&root->right==NULL)return true;
            return false;
        }
    };
    

    检查两棵树是否结构和值都相同
    两指针同时遍历对比即可。

    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        bool isSameTree(TreeNode *p, TreeNode *q) {
            if(p==NULL&&q==NULL)return true;
            if(p&&q)
            {
                if(p->val==q->val)
                {
                    bool l=false,r=false;
                    if(p->left&&q->left)l=isSameTree(p->left,q->left);
                    else if(p->left==NULL&&q->left==NULL)l=true;
                    if(p->right&&q->right)r=isSameTree(p->right,q->right);
                    else if(p->right==NULL&&q->right==NULL)r=true;
                    return l&&r;
                }
                return false;
            }
            return false;
        }
    };
    
  • 相关阅读:
    入门级: WinForm 下的 ComboBox,ListBox 的使用 (一)
    C#:谨慎 DateTime.Now 带来的危险
    HTML5 小游戏审核通过,请各位有兴趣的朋友帮忙投票!谢谢。
    基于fpga的单线激光雷达数据处理
    左右法则-复杂指针解析
    智能指针(auto_ptr和shared_ptr) 转
    iphone游戏引擎
    C++对象和内存
    让你的代码变的更加强大
    Class Loader
  • 原文地址:https://www.cnblogs.com/kuronekonano/p/11135657.html
Copyright © 2011-2022 走看看