赞
踩
二叉树的最小深度
递归遍历每个节点并计数深度,遍历到叶子节点时更新最小深度,并返回,非叶子节点取返回值的最小深度返回
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; } };
给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subtree-of-another-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def check (self, s, t): if t==None or s==None: return t==s ans = False if s.val == t.val: ans = True else: return False return ans and self.check(s.left,t.left) and self.check(s.right,t.right) def isSubtree(self, s: TreeNode, t: TreeNode) -> bool: ans = False if t == None or s==None: return False if s.val == t.val: ans = self.check(s,t) return ans or self.isSubtree(s.left,t) or self.isSubtree(s.right,t)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。