两种框架:
一、深度优先遍历:
1.前序遍历
2.中序遍历
3.后序遍历
二、广度优先遍历
层序遍历(迭代,队列实现)
三种方法:递归,迭代,Morris 遍历
栈可以实现递归
中序遍历
/**
* 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:
void traversal_mid(TreeNode *root,vector<int>&v)
{
if(root==NULL) return ;
traversal_mid(root->left,v);
v.push_back(root->val);
traversal_mid(root->right,v);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int>v;
traversal_mid(root,v);
return v;
}
};
前序遍历
class Solution {
public:
void traversal_pre(TreeNode *root,vector<int>&v)
{
if(root==NULL)
return ;
v.push_back(root->val);
traversal_pre(root->left,v);
traversal_pre(root->right,v);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> v;
traversal_pre(root,v);
return v;
}
};
后序遍历
class Solution {
public:
void traversal_post(TreeNode *root,vector<int>&v)
{
if(root==NULL) return ;
traversal_post(root->left,v);
traversal_post(root->right,v);
v.push_back(root->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> v;
traversal_post(root,v);
return v;
}
};
一、中序遍历:
看了随想录的:
一个是if代替while,注意在最外层while中加的条件是p!=NULL||!empty()因为,这两个中有一个不是空都说明树中还有没有遍历完的!
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> v;
TreeNode *p=root;
while(p||!st.empty()){
if(p)
{
st.push(p);
p=p->left;
}else{
p=st.top();
st.pop();
v.push_back(p->val);
p=p->right;
// st.push(p);//1 null 2 3不进的话,直接到第一个栈为空了
}
}
return v;
}
};
我的:使用的while!
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> v;
TreeNode *p=root;
st.push(p);
while(!st.empty()){
while(p)
{
p=p->left;
st.push(p);
}
p=st.top();
st.pop();
if(p){
v.push_back(p->val);
p=p->right;
st.push(p);
}
}
return v;
}
};
二、先序遍历
王道做法:
这个在随想录中序基础上修改一下访问位置即可。
注意:
while(p||!st.empty())
因为这里while的判断条件有p,所以不需要先进根节点,如果只有while(!st.empty())则需要先进一个根节点。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> v;
TreeNode *p=root;
//空指针不入栈!!
//因为这里while的判断条件有p,所以不需要先进根节点,如果只有while(!st.empty())则需要先进一个根节点
while(p||!st.empty()){
if(p){
st.push(p);
v.push_back(p->val);
p=p->left;
}else{
p=st.top();
st.pop();
p=p->right;
}
}
return v;
}
};
随想录做法:
先访问当前结点,再进栈右孩子,再进栈左孩子,因为这样才由先进后出的栈规则,先遍历左孩子,再遍历右孩子。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> v;
if(root==NULL) return v; //!!!!不要忘记!!!否则会有空指针->val
st.push(root);
while(!st.empty()){
TreeNode* p= st.top();
st.pop();
v.push_back(p->val);
if(p->right) st.push(p->right);
if(p->left) st.push(p->left);
}
return v;
}
};
我的做法:
对比我写的,我没有想到这种方法,我是直接访问一个进栈一个,然后再出栈,到头了之后再指向右孩子,这个做法和上面的中序遍历一样(我的中序遍历就是在我写的先序遍历基础上改了一下访问顺序),我写的空指针会进栈。
而随想录这种方法,不需要while循环,直接每次在访问的时候就对进栈出栈处理,注意该方法是空指针不进栈。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> v;
TreeNode *p=root;
// v.push_back(root->val);
st.push(p);
while(!st.empty()){
while(p)
{
st.push(p);
v.push_back(p->val);
p=p->left;
}
p=st.top();
st.pop();
if(p)
p=p->right;
}
return v;
}
};
三、后序遍历
随想录:
先序遍历是中左右,后序遍历是左右中,所以在先序的基础上改变入栈的顺序,变为中右左,再进行反转就变成了左右中。
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> v;
if(root==NULL) return v;
st.push(root);
while(!st.empty()){
TreeNode* p= st.top();
st.pop();
v.push_back(p->val);
if(p->left) st.push(p->left);
if(p->right) st.push(p->right);
}
reverse(v.begin(),v.end());
return v;
}
};
王道后序遍历迭代:
思路:
因为要先遍历左子树,再遍历右子树,最后遍历根结点,所以先是左子树全部进栈,再右子树全部进栈,什么时候访问呢?如果当前结点右子树为NULL或者右子树已经被访问完毕,则访问该结点。因此还需要用一个指针记录上一个访问过的结点,如果不这样的话会进入死循环!!(可看我写的错误的那个)
注意:
为什么最后要把P=NULL,因为访问了当前的结点,说明该节点的左子树已经被访问过了,所以置空后,不会继续死循环执行if(p ),会执行右子树,所以也不能将p=ST.top(),因为这样p不为空,还是会重复遍历左子树。
为什么要使用一个结点记录刚刚被访问过的结点?
因为访问当前结点时,该结点的父亲已经被加入 ,所以当访问完之后,回退到父亲节点,此时该父亲节点的左右子树都被访问完了,如果没有r的话,那么会死循环,又重新访问左子树,所以要用r记录该父亲节点的右子树北方问过了,接下来该访问该父亲节点,然后将p=NULL。
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> v;
TreeNode *p=root;
TreeNode *r=p;
while(p||!st.empty())
{
if(p){
st.push(p);
p=p->left;
}else {//p==NULL
p=st.top();
if(p->right&&p->right!=r)
{
p=p->right;
// st.push(p); 王道有这两句,但是没有这两句也可以,因为是循环会在if(p)那里执行这一条
// p=p->left;
}else{
v.push_back(p->val);
r=p; //访问过的结点,就是在访问后用r指向刚刚访问过的结点
st.pop();
p=NULL; //这里访问过后,必须将遍历结点置空,注意这里不能是p=st.top(),因为这样的话又会重新遍历当前结点的左子树,即死循环了
}
}
}
return v;
}
};
我写的死循环了!!注意用一个记录一下上一次访问过的结点
class Solution {
public:
vector postorderTraversal(TreeNode* root) {
stack
vector v;
TreeNode *p=root;
while(p||!st.empty())
{
if ( p )
{
st.push(p );
p=p->left;
}else {//p==NULL
p=st.top();
if(p->right)
{
p=p->right;
}else{
v.push_back(p->val);
st.pop();
p=st.top();//!!这里就会左边死循环,因为已经访问过了
// st.push(p);
}
}
}
return v;
}
};
Morris 遍历未学!!!!!!!!!!!!!!!!!!!还有后序遍历的评论,有一个人说的很有道理!!!!!!!!记得看!!!
中序遍历:
因为中序遍历结点进栈和处理时候不一样,所以使用标记法,加入中间结点的时候就紧跟着加入一个NULL
见随想录
感觉这种和层序遍历没啥区别,只不过利用了顺序变了,人家是队列罢了。
后续遍历:
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
if (root == NULL) return result;
st.push(root);
while (!st.empty()) {
TreeNode * p=st.top();
if(p){
st.pop();
st.push(p);
st.push(NULL);
if(p->right) st.push(p->right);
if(p->left) st.push(p->left);
}else{
st.pop(); //空指针出栈
p=st.top();
st.pop();
result.push_back(p->val);
}
}
return result;
}
};
//左右中
**此题目为模板!!!**
层序遍历模板【随想录】
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
queue<TreeNode*> que;
if (root != NULL) que.push(root);
vector<vector<int>> result;
while (!que.empty()) {
int size = que.size();
vector<int> vec;
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
vec.push_back(node->val);
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result.push_back(vec);
}
reverse(result.begin(), result.end()); // 在这里反转一下数组即可
return result;
}
};
102. 二叉树的层序遍历
题目
没有思路,看的随想录写的:
注意:不要写成q.size(),因为q.size()是不断变化的,要想遍历的是每一层的结点,就每次提前将q.size()存下来,只遍历这层的。
新思路:队列中元素的个数就是一层元素的个数
我的思路复盘:
一直想着怎么才能找到一层的最后一个,开始想用数字统计个数,不可行。
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
if(root==NULL) return{};
queue<TreeNode*> q;
vector<int> v;
vector<vector<int>> result;
q.push(root);
TreeNode *p=NULL;
while(!q.empty()){
int size=q.size();
//vectorv; 则不需要下面的v.clear()
for(int i=0;i<size;i++) //不要写成q.size(),因为q.size()是不断变化的
{
p=q.front();
q.pop();
v.push_back(p->val);
if(p){
if(p->left)
q.push(p->left);
if(p->right)
q.push(p->right);
}
}
result.push_back(v);
v.clear();//或者直接在上面while内初始化一个vector
}
return result;
}
};
递归解法:
【随想录】
并不是严格意义上的层序遍历,因为没有按照层序遍历的顺序,只不过答案一样。
eg:即题目第一个样例
root = [3,9,20,null,null,15,7]
递归过程:(result数组变化)
理顺逻辑!
思路:
depth是记录当前的层数的,注意result中的个数就是已经遍历了几层了。思路见代码注释。
新思路:如何在递归过程中建立新的数组,要找到规律,即什么时候该建立新的数组了,这里result.size()和层数相等时。
class Solution {
public:
void traversal(TreeNode * cur, vector<vector<int>>&result,int depth)
{
//递归出口是当前结点是空结点
if(cur==NULL) return ;
if(depth==result.size()) result.push_back(vector<int>()); //result中的个数就是已经遍历了几层,如果和层数相等的话,就新建一个空的vector加入。注意这里如何在递归的时候新建一个数组
result[depth].push_back(cur->val);//每次cur代表当前遍历的结点,depth代表当前cur所在层数,所以就把当前的cur加入到该depth层中。
//分别对cur的左孩子和右孩子进行递归
traversal(cur->left,result,depth+1);//每次指向下一个左右孩子就相当于又进入到下一层了,所以depth+1
traversal(cur->right,result,depth+1);
}
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
int depth=0;
traversal(root,result,depth);
return result;
}
};
题目
注意:用reverse函数反转vectorvector>类型时,只会反转大的,小的vector不会反转。且reverse函数是没有返回值的是void,所以不可以直接return reverse(result.begin(),result.end());
我用的是列了个栈进行反转。
新思路:解答一个正常思路变形的题的时候,可以先按照正常思路来,比如这道题就是层序遍历,只不过再反转一下就好,所以可以先用正常思路解答,然后看是否可以在正常解答的答案基础上进行变化,得到正常题目变形后的答案
在层序遍历上反转一下即可。
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
if(root==NULL) return {};//特别注意这一步!!否则会有空指针进循环
queue<TreeNode *> q;
vector<vector<int>> result;
TreeNode *p=NULL;
q.push(root);
while(!q.empty())
{ vector<int> v;
int size=q.size();
for(int i=0;i<size;i++)
{
p=q.front();
q.pop();
v.push_back(p->val);
if(p->left) q.push(p->left);
if(p->right) q.push(p->right);
}
result.push_back(v);
}
reverse(result.begin(),result.end());
return result;
}
};
方法二:DFS见评论区,待学
模板,找到二叉树中每层最后一个结点,DFS用递归,BFS使用迭代
题目
我写的:
思路复盘:
即每一层取一个最后一个结点。当时我还没想到是最后一个,我是根据“右视图”这个概念,只是想到每一层取一个结点,即先看右子树是否为空,为空则取左子树,因此先进队右子树,再进队左子树,然后设置一个数组,该数组事先不知道根据提示最大为101个,然后做标记即如果是-200说明本层还没有找到最后一个结点。
其实不应该被题目右视图这个花里胡哨欺骗,应该看到本质是求什么,用一句话表示清楚,然后再想解题算法,再想基础算法,和数据结构。这个题目是层序遍历的应用,即变形一下即可。
并且我是投机取巧了,不知道树的高度,所以设置了一个很大的数组,浪费了空间。
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
if(root==NULL) return{} ;
queue<TreeNode *> q;
TreeNode *p=NULL;
q.push(root);
vector<int> v(101,-200);
v[0]=root->val;
int depth=1;
while(!q.empty())
{
int size=q.size();
for(int i=0;i<size;i++)
{
p=q.front();
q.pop();
if(p->right){ q.push(p->right); } //先遍历右子树再看左子树
if(p->left) {q.push(p->left); }
if(v[depth]==-200)
{
if(p->right)
v[depth]=p->right->val;
else if(p->left) v[depth]=p->left->val;
}
}
depth++;
}
v.resize(depth-1);
return v;
}
};
DFS:深度优先遍历——先序
看了评论区我写的:
思路:
因为每次进一层循环都会depth++,如果是回退的话,会继续执行上一层的遍历左子树,而在遍历左子树的时候,depth由于已经将右子树遍历了,所以depth已经增加过了,所以depth!=v,size(),因为每次相等之后,depth都增加一(depth初始值是0)所以只有第一次遍历右子树的时候,才将该节点放入v里。
注意:这里和之前的层序遍历中递归调用时如何创建空的vector思路是一样的,depth记录的是递归的深度,也是树的层数。因为这里是先遍历的右子树,所以每次进到下一个新层时,最先遍历的都是右子树的结点。
class Solution{
public:
void traversal(TreeNode *cur ,int depth,vector<int>&v){
if(cur==NULL) return;
if(depth==v.size()) v.push_back(cur->val);
depth++;
traversal(cur->right,depth,v);
traversal(cur->left,depth,v);
}
vector<int> rightSideView(TreeNode* root) {
vector<int> v;
int depth=0;
traversal(root,depth,v);
return v;
}
};
BFS评论区:
如何找到最后一个节点,就是在遍历每层的结点时,当i==size-1,则该结点就是层次遍历的最后一个结点。
反思: BFS解法不用去预先定义depth有多大,而是直接将最后一个加入即可
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
if(root==NULL) return{} ;
queue<TreeNode *> q;
TreeNode *p=NULL;
q.push(root);
vector<int> v;
while(!q.empty())
{
int size=q.size();
for(int i=0;i<size;i++)
{
p=q.front();
q.pop();
if(p->left) q.push(p->left);
if(p->right) q.push(p->right);
if(i==size-1) //最后一个结点
v.push_back(p->val);
}
}
return v;
}
};
题目
方法一:BFS:
模板要熟练!!!!!!!!
bug点:
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
queue<TreeNode *>que;
vector<double> v;
if(root!=NULL) que.push(root); ///特别注意这里!!直接是不空加入root即可
double sum=0;
while(!que.empty())
{
int size=que.size();
for(int i=0;i<size;i++)
{
TreeNode * p=que.front();
que.pop();
sum+=p->val;
if(p->left) {que.push(p->left);}
if(p->right) {que.push(p->right);}
}
v.push_back(sum/size);
sum=0;
}
return v;
}
};
方法二:DFS (先序)
看的官方题解:
这里重点关注depth与sum数组个数的问题,和之前的vector
depth==sum.size():当前层遍历完毕,此时cur为当前层的最后一个结点。
注意
注意这里必须有第一个,因为后面都是[]下标这个取值符号,vector不知道个数的话是不能用[depth]来取值的!!和默认初始化都是0无关!vector初始化没有固定值的话(vectorv(0,1000)),所以不能用[ ],有了第一个后面才能用[depth]
sum.push_back(cur->val);
counts.push_back(1);
class Solution {
public:
void DFS(TreeNode * cur, int depth ,vector<double>&sum,vector<int>&counts){
if(cur==NULL) return;
if(depth<sum.size())
{
sum[depth]+=cur->val;
counts[depth]++;
}
else{ //到了新一层,初始化一下,在第一个结点基础上累加。如果没有这个的话,注意这里必须有第一个,因为后面都是[]下标这个取值符号,vector不知道个数的话是不能用[depth]来取值的!!和默认初始化都是0无关!
sum.push_back(cur->val);
counts.push_back(1);
}
depth++;//进入新一层即又要重新开始遍历左子树右子树时depth才加一。
DFS(cur->left,depth,sum,counts);
DFS(cur->right,depth,sum,counts);
}
vector<double> averageOfLevels(TreeNode* root) {
vector<double>sum;
vector<int>counts;
vector<double> result;
int depth=0;
DFS(root,depth,sum,counts);
for(int i=0;i<sum.size();i++)
{
result.push_back(sum[i]/counts[i]);
}
return result;
}
};
题目
注意:N叉树的定义,使用一个数组记录child
class Node {
public:
int val;
vector
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, vector _children) {
val = _val;
children = _children;
}
};
/*
// Definition for a Node.
class Node {
public:
int val;
vector children;
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, vector _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public:
vector<vector<int>> levelOrder(Node* root) {
queue<Node*> q;
if(root) q.push(root);
vector<vector<int>> result;
while(!q.empty())
{
int size=q.size();
vector<int> v;
for(int i=0;i<size;i++)
{
Node *p=q.front();
q.pop();
v.push_back(p->val);
for(int k=0;k<p->children.size();k++)
if(p->children[k]!=NULL)
q.push(p->children[k]);
}
result.push_back(v);
}
return result;
}
};
题目
BFS:
class Solution {
public:
vector<int> largestValues(TreeNode* root) {
vector<int> result;
queue<TreeNode*>q;
if(root) q.push(root);
while(!q.empty())
{
int size=q.size();
int maxnum=INT_MIN;
for(int i=0;i<size;i++)
{
TreeNode *p=q.front();
q.pop();
if(p->val>maxnum) maxnum=p->val;
if(p->left) q.push(p->left);
if(p->right) q.push(p->right);
}
result.push_back(maxnum);
}
return result;
}
};
DFS:
class Solution {
public:
void DFS(TreeNode *cur,int depth,vector<int>&result)
{
if(cur==NULL) return ;
///用第一个充当每行的最大值,然后不断用当前cur与result[depth]作比较
if(result.size()==depth)//到底是最后一个还是下一层第一个?
{
result.push_back(cur->val);
}
else{
result[depth]=max(result[depth],cur->val);//覆盖!
}
DFS(cur->left,depth+1,result);
DFS(cur->right,depth+1,result);
}
vector<int> largestValues(TreeNode* root) {
vector<int> result;
int depth=0;
int max=INT_MIN;
DFS(root,depth,result);
return result;
}
};
题目
方法一:层次遍历
官方思路:在遍历的过程中就将next填充好
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() : val(0), left(NULL), right(NULL), next(NULL) {}
Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
*/
class Solution {
public:
Node* connect(Node* root) {
queue<Node *> q;
if(root) q.push(root);
while(!q.empty())
{
int size=q.size();
for(int i=0;i<size;i++)
{
Node *p=q.front();
q.pop();
if(i<size-1) //不是最后一个就填充next
p->next=q.front();
if(p->left)
{
q.push(p->left);
}
if(p->right)
{
q.push(p->right);
}
}
}
return root;
}
};
我写的:
将每一层放到一个vector数组里,然后再填充next,每一层就相当于一个单链表。多了空间复杂度。
class Solution {
public:
Node* connect(Node* root) {
queue<Node *> q;
if(root) q.push(root);
while(!q.empty())
{
int size=q.size();
vector<Node*>v;
for(int i=0;i<size;i++)
{
Node *p=q.front();
q.pop();
v.push_back(p);
Node *node=p;
if(p->left) q.push(p->left);
if(p->right) q.push(p->right);
}
for(int j=0;j<size-1;j++)
{
v[j]->next=v[j+1];
}
v[size-1]->next=NULL;
}
return root;
}
};
随想录:
class Solution {
public:
Node* connect(Node* root) {
queue<Node*> que;
if (root != NULL) que.push(root);
while (!que.empty()) {
int size = que.size();
// vector vec;
Node* nodePre;
Node* node;
for (int i = 0; i < size; i++) {
if (i == 0) {
nodePre = que.front(); // 取出一层的头结点
que.pop();
node = nodePre;
} else {
node = que.front();
que.pop();
nodePre->next = node; // 本层前一个节点next指向本节点
nodePre = nodePre->next;
}
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
nodePre->next = NULL; // 本层最后一个节点指向NULL
}
return root;
}
};
看了官方第二种方法:利用上一层的next来构建下一层的next,
写的一个DFS递归。
思路:
因为是完全二叉树,所以有两种情况,一种是同一个父亲节点的,则cur->left=cur->right; 一种是不同结点的即表兄弟,则利用上一层的next来指向,cur->right->next=cur->next->left;
class Solution {
public:
void DFS(Node *cur)
{
if(cur==NULL) return ;
if(cur->left)
cur->left->next=cur->right;
if(cur->next&&cur->right)
cur->right->next=cur->next->left;
DFS(cur->left);
DFS(cur->right);
}
Node* connect(Node* root) {
Node *p=root;
DFS(root);
return root;
}
};
官方:
class Solution {
public:
Node* connect(Node* root) {
if (root == nullptr) {
return root;
}
// 从根节点开始
Node* leftmost = root;
while (leftmost->left != nullptr) {
// 遍历这一层节点组织成的链表,为下一层的节点更新 next 指针
Node* head = leftmost;
while (head != nullptr) {
// CONNECTION 1
head->left->next = head->right;
// CONNECTION 2
if (head->next != nullptr) {
head->right->next = head->next->left;
}
// 指针向后移动
head = head->next;
}
// 去下一层的最左的节点
leftmost = leftmost->left;
}
return root;
}
};
普通二叉树
题目
方法一:层次遍历
使用队列的思路和上一个完全二叉树的代码一样。因为队列直接进的就是从左到右一层的结点。
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() : val(0), left(NULL), right(NULL), next(NULL) {}
Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
*/
class Solution {
public:
Node* connect(Node* root) {
queue<Node *>q;
if(root) q.push(root);
while(!q.empty())
{
int size=q.size();
for(int i=0;i<size;i++)
{
Node *p=q.front();
q.pop();
if(i<size-1) p->next=q.front();
if(p->left) q.push(p->left);
if(p->right) q.push(p->right);
}
}
return root;
}
};
方法二:利用上一层已知的next数组来填充
未理解
题目
方法一:层序遍历
class Solution {
public:
int maxDepth(TreeNode* root) {
queue<TreeNode*>q;
if(root) q.push(root);
int depth=0;
while(!q.empty())
{
int size=q.size();
for(int i=0;i<size;i++)
{
TreeNode *p=q.front();
q.pop();
if(p->left) q.push(p->left);
if(p->right) q.push(p->right);
}
depth++;
}
return depth;
}
};
DFS
后序遍历:分别递归遍历左右子树的深度,找到最大的,再回到本层,加上当前节点。
class Solution {
public:
int postOrder(TreeNode *root)
{
if(root==NULL) return 0;
int left=postOrder(root->left);
int right=postOrder(root->right);
int maxnum=max(left,right);
return maxnum+1;
}
int maxDepth(TreeNode* root) {
return postOrder(root);
}
};
后序遍历精简版,体现不了后序遍历
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root==NULL) return 0;
return max(maxDepth(root->left),maxDepth(root->right))+1;
}
};
先序遍历:
深刻体现了递归的回溯。注意这里使用了result全局变量,来记录比较每一层的depth是回溯的depth还是往下递归深一层的depth。
题目
BFS:
注意题目条件是叶子!!这是重要的关键信息,所以只要遍历到某一层中有叶子,那就返回depth!
class Solution {
public:
int minDepth(TreeNode* root) {
queue<TreeNode*>q;
if(root) q.push(root);
int depth=0;
while(!q.empty())
{
int size=q.size();
for(int i=0;i<size;i++)
{
TreeNode *p=q.front();
q.pop();
if(p->left) q.push(p->left);
if(p->right) q.push(p->right);
if(p->left==NULL&&p->right==NULL) return depth+1;
}
depth++;
}
return depth;
}
};
DFS:
看的官方后面的精选解析 解析
感觉就是分辨不同的条件!
class Solution {
public:
int minDepth(TreeNode* root) {
if(root==NULL) return 0;
if(root->left==NULL&&root->right==NULL) return 1; //题目关键信息叶子节点!
int m1=minDepth(root->left);
int m2=minDepth(root->right);
//左右子树有一个是空,则m1,m2一定有一个是0,返回的是不为空的子树的深度,这里使用了m1+m2+1的形式或者max(m1,m2)+1;
if(root->left==NULL||root->right==NULL) return max(m1,m2)+1;
return min(m1,m2)+1;
}
};
后续遍历, 自己写的 对比随想录,随想录是真正的后续遍历,因为是根据返回的leftdepth和rightdepth的结果来进行的后续操作。
自己写的:
class Solution {
public:
int postOrder(TreeNode* root)
{
if(root==NULL) return 0;
if(root->left==NULL&&root->right!=NULL) return postOrder(root->right)+1;
if(root->left!=NULL&&root->right==NULL) return postOrder(root->left)+1;
if(root->left==NULL&&root->right==NULL) return 1;
int left=postOrder(root->left);
int right=postOrder(root->right);
return min(left,right)+1;
}
int minDepth(TreeNode* root) {
return postOrder(root);
}
};
随想录:
class Solution {
public:
int postOrder(TreeNode* root)
{
if(root==NULL) return 0;
int left=postOrder(root->left);
int right=postOrder(root->right);
if(root->left==NULL&&root->right!=NULL) return right+1;
if(root->left!=NULL&&root->right==NULL) return left+1;
if(root->left==NULL&&root->right==NULL) return 1;
return min(left,right)+1;
}
int minDepth(TreeNode* root) {
return postOrder(root);
}
};
题目
class Solution {
public:
vector<int> postorder(Node* root) {
if(root==NULL) return{};
stack<Node *>st;
vector<int> result;
st.push(root);
while(!st.empty())
{
Node* p=st.top();
st.pop();
result.push_back(p->val);
for(int i=0;i<p->children.size();i++)
{
if(p->children[i])
st.push(p->children[i]);
}
}
reverse(result.begin(),result.end());
return result;
}
};
递归
class Solution {
public:
void DFS(Node *root,vector<int>&result)
{
if(root==NULL) return ;
for(int i=0;i<root->children.size();i++)
{
if(root->children[i])
DFS(root->children[i],result);
}
result.push_back(root->val);
}
vector<int> postorder(Node* root) {
vector<int> result;
DFS(root,result);
return result;
}
};
官方题解还有两种方法
题目
我写的:
迭代
class Solution {
public:
vector<int> preorder(Node* root) {
if(root==NULL) return{};
stack<Node *>st;
vector<int> result;
st.push(root);
while(!st.empty())
{
Node* p=st.top();
st.pop();
result.push_back(p->val);
for(int i=p->children.size()-1;i>=0;i--)
{
if(p->children[i])
st.push(p->children[i]);
}
}
return result;
}
};
递归
result写在外面用的而全局变量,效率极低
class Solution {
public:
vector<int> result;
vector<int> preorder(Node* root) {
if(root==NULL) return{};
result.push_back(root->val);
for(int i=0;i<root->children.size();i++)
{
if(root->children[i])
preorder(root->children[i]);
}
return result;
}
};
传参数的话效率高一点
class Solution {
public:
void DFS(Node *root,vector<int>&result)
{
if(root==NULL) return ;
result.push_back(root->val);
for(int i=0;i<root->children.size();i++)
{
if(root->children[i])
DFS(root->children[i],result);
}
}
vector<int> preorder(Node* root) {
vector<int> result;
DFS(root,result);
return result;
}
};
题目
看的随想录写的:一直有一个bug就是每一层重新赋值result儿不是把result当成全局变量。因为每次找的是当前节点root中的孩子子树们中最大的深度,然后再return+1;如果设置成全局变量,那就是每次将拥有最大深度的孩子的深度与当前孩子的深度比较???为啥错
class Solution {
public:
//int result=0;
int postOrder(Node *root)
{
if(root==NULL) return 0;
int result=0;
for(int i=0;i<root->children.size();i++)
{
int num=postOrder(root->children[i]);
result=result<num?num:result;
}
return result+1;
}
int maxDepth(Node* root) {
return postOrder(root);
}
};
错误的
class Solution {
public:
int result=0;
void postOrder(Node *root,int depth)
{
result=max(result,depth);
if(root==NULL) return;
for(int i=0;i<root->children.size();i++)
{
depth++;
postOrder(root->children[i],depth);
depth--;
}
}
int maxDepth(Node* root) {
postOrder(root,0);
return result;
}
};
迭代法:
class Solution {
public:
int maxDepth(Node* root) {
queue<Node*> que;
if(root) que.push(root);
int depth=0;
while(!que.empty())
{
int size=que.size();
for(int i=0;i<size;i++)
{
Node *node=que.front();
que.pop();
for(int j=0;j<node->children.size();j++)
que.push(node->children[j]);
}
depth++;
}
return depth;
}
};