树遍历(先序,中序,后序,层序)

一、树的遍历

两种框架:
一、深度优先遍历:
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 st;
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;
    }
};
//左右中 

二叉树层序遍历

**此题目为模板!!!**
层序遍历模板【随想录】

  • for循环是遍历一层,遍历完一层要做什么就在for循环外面做修改
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数组变化)

  1. {3}
  2. {3},{9}
  3. {3},{9}, 9的左孩子是空直接return
  4. {3}, {9} ,9的右孩子是空直接return
  5. {3},{9},{15} 回退后,开始递归遍历3->right,加入20的左孩子
  6. {3},{9},{15},15的左右孩子是空,直接return
  7. {3},{9},{15},遍历7的左右孩子是空,直接return
  8. {3},{9},{15,7},加入20的右孩子7
  9. {3},{9,20},{15,7} ,加入20
    可以看出递归的时候,并没有把一层的结点都遍历完,而是在递归的过程中逐步加入遍历的结点。

理顺逻辑!

思路:
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;        
        }
};

107. 二叉树的层序遍历 II

题目
注意:用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见评论区,待学

199. 二叉树的右视图

模板,找到二叉树中每层最后一个结点,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;
    }
};

637. 二叉树的层平均值

题目
方法一:BFS:
模板要熟练!!!!!!!!
bug点:

  1. 注意sum必须使用double,int 不对
  2. vectorpush_back一个空的vector时,也可以用v.push_back({}),或者v.push_back(vector)
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;
    }
};

429. N 叉树的层序遍历

题目
注意:N叉树的定义,使用一个数组记录child
class Node {
public:
int val;
vector> children;

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;
    }
};

515. 在每个树行中找最大值

题目
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;
    }
};

116. 填充每个节点的下一个右侧节点指针

题目
方法一:层次遍历
官方思路:在遍历的过程中就将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;
    }
};


117. 填充每个节点的下一个右侧节点指针 II

普通二叉树
题目
方法一:层次遍历
使用队列的思路和上一个完全二叉树的代码一样。因为队列直接进的就是从左到右一层的结点。

/*
// 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数组来填充
未理解

104. 二叉树的最大深度

题目
方法一:层序遍历

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。

111. 二叉树的最小深度

题目
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);
    }
};

590. N 叉树的后序遍历

题目

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;
        }
       
    
};

官方题解还有两种方法

589. N 叉树的前序遍历

题目
我写的:
迭代

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;
        }
       
    
};

559. N 叉树的最大深度

题目
看的随想录写的:一直有一个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;
    }
};

你可能感兴趣的:(力扣,算法)