层序遍历 10

借助队列,从一层开始,遍历每一层的每个元素出队进结果,左右孩子都入队,遍历完队列里只剩下一层的节点,保存节点个数,再遍历这一层得到下一层,直到队列为空。

C++

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> result;
        queue<TreeNode*> que;
        if (root == nullptr) return result;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            vector<int> vec;
            while (size--) {
                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);
        }
        return result;
    }
};

C#


public class Solution {
    public IList<IList<int>> LevelOrder(TreeNode root) {
        List<IList<int>> result = new List<IList<int>>();
        Queue<TreeNode> que = new Queue<TreeNode>();
        if (root == null) return result;
        que.Enqueue(root);
        while (que.Count != 0) {
            int size = que.Count;
            List<int> vec = new List<int>();
            while(size-- > 0) {
                TreeNode cur = que.Dequeue();
                vec.Add(cur.val);
                if(cur.left != null) que.Enqueue(cur.left);
                if(cur.right != null) que.Enqueue(cur.right);
            }
            result.Add(vec);
        }
        return result;
    }
}

107层序遍历2

要求从最后一层向上从左到右输出,reverse一下就行了。

//C++
reverse(res.begin(), res.end());
//C#
result.Reverse(0, result.Count);

199二叉树的右视图

层序遍历的时候在每一层末节点记录值即可。

//C++
class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        queue<TreeNode*> que;
        vector<int> res;
        if (root == nullptr) return res;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            while (size--) {
                TreeNode* cur= que.front();
                if (size == 0) {
                    res.push_back(cur->val);
                }           
                que.pop();
                if (cur->left != nullptr) que.push(cur->left);
                if (cur->right != nullptr) que.push(cur->right);
            }
        }
        return res;
    }
};
//C#
public class Solution {
    public IList<int> RightSideView(TreeNode root) {
        Queue<TreeNode> que = new Queue<TreeNode>();
        List<int> res = new List<int>();
        if (root == null) return res;
        que.Enqueue(root);
        while (que.Count != 0) {
            int size = que.Count;
            for (int i = 0; i < size; i++) {
                TreeNode cur = que.Dequeue();
                if (i == size - 1) res.Add(cur.val);
                if (cur.left != null) que.Enqueue(cur.left);
                if (cur.right != null) que.Enqueue(cur.right);
            }
        }
        return res;
    }
}

637二叉树的层平均值

写个sum记录下每层的平均值即可。

//C++
class Solution {
public:
    vector<double> averageOfLevels(TreeNode* root) {
        vector<double> res;
        queue<TreeNode*> que;
        if (root == nullptr) return res;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            double cnt = size;
            long sum = 0;
            while (size--) {
                TreeNode* cur = que.front();
                que.pop();
                sum += cur->val;
                if (cur->left != nullptr) que.push(cur->left);
                if (cur->right != nullptr) que.push(cur->right);
            }
            res.push_back(sum / cnt);
        }
        return res;
    }
};
//C#

public class Solution {
    public IList<double> AverageOfLevels(TreeNode root) {
        Queue<TreeNode> que = new Queue<TreeNode>();
        List<double> res = new List<double>();
        if (root == null) return res;
        que.Enqueue(root);
        while (que.Count != 0) {
            int size = que.Count;
            double sum = 0;
            for (int i = 0; i < size; i++) {
                TreeNode cur = que.Dequeue();
                sum += cur.val;
                if (cur.left != null) que.Enqueue(cur.left);
                if (cur.right != null) que.Enqueue(cur.right);
            }
            res.Add(sum / size);
        }
        return res;
    }
}

429 N叉树的层序遍历

遍历左右子树变成遍历所有子树即可。

//C++
class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) {
        vector<vector<int>> res;
        queue<Node*> que;
        if (root == nullptr) return res;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            vector<int> vec;
            while (size--) {
                Node* cur = que.front();     
                que.pop();
                vec.push_back(cur->val);
                for (int i = 0; i < cur->children.size(); i++) {
                    if (cur->children[i] != nullptr) que.push(cur->children[i]);
                }
            }
            res.push_back(vec);
        }
        return res;
    }
};
//C#
public class Solution {
    public IList<IList<int>> LevelOrder(Node root) {
        Queue<Node> que = new Queue<Node>();
        IList<IList<int>> res = new List<IList<int>>();
        if (root == null) return res;
        que.Enqueue(root);
        while (que.Count != 0) {
            int size = que.Count;
            List<int> vec = new List<int>();
            for (int i = 0; i < size; i++) {
                Node cur = que.Dequeue();
                vec.Add(cur.val);
                for (int j = 0; j < cur.children.Count; j++) {
                    if (cur.children[j] != null) que.Enqueue(cur.children[j]);
                }
                
            }
            res.Add(vec);
        }
        return res;
    }
}

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

每一层记录最大值即可。

//C++
class Solution {
public:
    vector<int> largestValues(TreeNode* root) {
        vector<int> res;
        queue<TreeNode*> que;
        if (root == nullptr) return res;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            int max = INT_MIN;
            while (size--) {
                TreeNode* cur = que.front();
                que.pop();
                if (cur->val > max) max = cur->val;
                if (cur->left != nullptr) que.push(cur->left);
                if (cur->right != nullptr) que.push(cur->right);
            }
            res.push_back(max);
        }
        return res;
    }
};
//C#
public class Solution {
    public IList<int> LargestValues(TreeNode root) {
        List<int> res = new List<int>();
        Queue<TreeNode> que = new Queue<TreeNode>();
        if (root == null) return res;
        que.Enqueue(root);
        while (que.Count != 0) {
            int size = que.Count;
            int max = int.MinValue;
            while (size-- > 0) {
                TreeNode cur = que.Dequeue();
                if (cur.val > max) max = cur.val;
                if (cur.left != null) que.Enqueue(cur.left);
                if (cur.right != null) que.Enqueue(cur.right);
            }
            res.Add(max);
        }
        return res;
    }
}

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

遍历的时候指一下指针就行了。

//C++
class Solution {
public:
    Node* connect(Node* root) {
        queue<Node*> que;
        if (root == nullptr) return root;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            while (size--) {
                Node* node = que.front();
                que.pop();
                if (size == 0) {
                    node->next = nullptr;
                } else {
                    node->next = que.front();
                }
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
        }
        return root;
    }
};
//C#
public class Solution {
    public Node Connect(Node root) {
        Queue<Node> que = new Queue<Node>();
        if (root == null) return root;
        que.Enqueue(root);
        while (que.Count != 0) {
            int size = que.Count;
            while (size-- > 0) {
                Node cur = que.Dequeue();
                if (size == 0) {
                    cur.next = null;
                } else {
                    cur.next = que.Peek();
                }
                if (cur.left != null) que.Enqueue(cur.left);
                if (cur.right != null) que.Enqueue(cur.right);
            }
        }
        return root;
    }
}

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

和上一题完全一样。

104. 二叉树的最大深度

层序遍历的时候记录层数即可。

//C++
class Solution {
public:
    int maxDepth(TreeNode* root) {
        queue<TreeNode*> que;
        if (root == nullptr) return 0;
        que.push(root);
        int depth = 0;
        while (!que.empty()) {
            int size = que.size();
            depth++;
            while (size--) {
                TreeNode* node = que.front();
                que.pop();
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
        }
        return depth;
    }
};
//C#
public class Solution {
    public int MaxDepth(TreeNode root) {
        Queue<TreeNode> que = new Queue<TreeNode>();
        if (root == null) return 0;
        que.Enqueue(root);
        int depth = 0;
        while (que.Count != 0) {
            int size = que.Count;
            depth++;
            while (size-- > 0) {
                TreeNode cur = que.Dequeue();
                if (cur.left != null) que.Enqueue(cur.left);
                if (cur.right != null) que.Enqueue(cur.right);
            }
            
        }
        return depth;
    }
}

111. 二叉树的最小深度

左右子树都为空时即达到最小深度。

//C++
/**
 * 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:
    int minDepth(TreeNode* root) {
                queue<TreeNode*> que;
        if (root == nullptr) return 0;
        que.push(root);
        int depth = 0;
        while (!que.empty()) {
            int size = que.size();
            depth++;
            while (size--) {
                TreeNode* node = que.front();
                que.pop();
                if (node->left == nullptr && node->right == nullptr) return depth;
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
        }
        return depth;
    }
};
//C#
public class Solution {
    public int MinDepth(TreeNode root) {
        Queue<TreeNode> que = new Queue<TreeNode>();
        if (root == null) return 0;
        que.Enqueue(root);
        int depth = 0;
        while (que.Count != 0) {
            int size = que.Count;
            depth++;
            while (size-- > 0) {
                TreeNode cur = que.Dequeue();
                if (cur.left == null && cur.right == null) return depth;
                if (cur.left != null) que.Enqueue(cur.left);
                if (cur.right != null) que.Enqueue(cur.right);
            }
            
        }
        return depth;
    }
}

226.翻转二叉树

递归

使用先序或者后序,中序会使第二次翻转反了,要两次左。

//C++
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if (root == nullptr) return root;
        swap(root->left, root->right);
        invertTree(root->left);
        invertTree(root->right);
        return root;
    }
};
//C#

public class Solution {
    public TreeNode InvertTree(TreeNode root) {
        if (root == null) return root;
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
        InvertTree(root.left);
        InvertTree(root.right);
        return root;
    }
}

二刷看一下迭代的非递归方法。

101.对称二叉树 2

递归三步走:

  • 确定递归参数和返回值,即左子树节点和右子树节点,返回值是bool。
  • 确定递归结束条件,左右子树有一个为空一个不为空,return false,都为空,return true,都不为空但不相等,return false,都不为空且相等,进入单层递归逻辑(如何使用下一层递归)。
  • 递归单层逻辑:比较二叉树外侧是否对称(不是比数值,而是真个子树,相当于调用下一层递归逻辑):传入的是左节点的左孩子,右节点的右孩子。 比较内测是否对称,传入左节点的右孩子,右节点的左孩子。 如果左右都对称就返回true ,有一侧不对称就返回false 。
class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if (root == nullptr) return true;
        else return compare(root->left, root->right);
    }
    bool compare(TreeNode* left, TreeNode* right) {
        if (left == nullptr && right != nullptr) return false;
        else if (left != nullptr && right == nullptr) return false;
        else if (left == nullptr && right == nullptr) return true;
        else if (left->val != right->val) return false;
        bool outside = compare(left->left, right->right);
        bool inside = compare(left->right, right->left);
        return outside && inside;
    }
};

二刷看看迭代法。

二刷

层序遍历模板

使用队列来维护元素动态变化的需求,其实栈和队列都是很好的动态容器,队列里放着当前层的元素,再自己遍历一遍就可以产生下一层的元素。

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        queue<TreeNode*> que;
        //0.为空直接返回空数组
        if (root == nullptr) return res;
        //1.放入头结点
        que.push(root);
        while (!que.empty()) {
            //记录本层节点数量
            int size = que.size();
            vector<int> data;
            //遍历每个节点,添加其左右子节点
            for (int i = 0; i < size; i++) {
                TreeNode* temp = que.front();
                data.push_back(temp->val);
                if (temp->left) que.push(temp->left);
                if (temp->right) que.push(temp->right);
                que.pop();
            }
            res.push_back(data);
        }
        return res;
    }
};

层序遍历2

自底向上遍历,reverse一下数组。

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> res;
        queue<TreeNode*> que;
        if (root == nullptr) return res;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            vector<int> data;
            for (int i = 0; i < size; i++) {
                TreeNode* temp = que.front();
                que.pop();
                data.push_back(temp->val);
                if (temp->left) que.push(temp->left);
                if (temp->right) que.push(temp->right);
            }
            res.push_back(data);
        }
        reverse(res.begin(), res.end());
        return res;
    }
};

二叉树的右视图

层序遍历的时候只收集最右边的节点。

    vector<int> rightSideView(TreeNode* root) {
        vector<int> res;
        queue<TreeNode*> que;
        if (root == nullptr) return res;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            for (int i = 0; i < size; i++) {
                TreeNode* temp = que.front();
                que.pop();
                if (i == size - 1) res.push_back(temp->val);
                if (temp->left) que.push(temp->left);
                if (temp->right) que.push(temp->right);
            }
        }
        return res;
    }

二叉树的层平均值

层序遍历取一下每一层的平均值,double是双精度浮点,long是长整形。

    vector<double> averageOfLevels(TreeNode* root) {
        vector<double> res;
        queue<TreeNode*> que;
        if (root == nullptr) return res;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            double sum = 0;
            for (int i = 0; i < size; i++) {
                TreeNode* temp = que.front();
                que.pop();
                sum += temp->val;
                if (temp->left) que.push(temp->left);
                if (temp->right) que.push(temp->right);
            }
            res.push_back(sum / size);
        }
        return res;
    }

在每个树层中找最大值

层序遍历记录每层最大值。

   vector<int> largestValues(TreeNode* root) {
        vector<int> res;
        queue<TreeNode*> que;
        if (root == nullptr) return res;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            int max = INT_MIN;
            while (size--) {
                TreeNode* temp = que.front();
                que.pop();
                if (temp->val > max) max = temp->val;
                if (temp->left) que.push(temp->left);
                if (temp->right) que.push(temp->right);
            }
            res.push_back(max);
        }
        return res;
    }

N叉树的层序遍历

遍历每一层的时候,因为是N叉树,所以遍历子节点从左右变成所有children数组。

    vector<vector<int>> levelOrder(Node* root) {
        queue<Node*> que;
        vector<vector<int>> res;
        if (root == nullptr) return res;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            vector<int> data;
            while (size--) {
                Node* temp = que.front();
                que.pop();
                data.push_back(temp->val);
                for (int i = 0; i < temp->children.size(); i++) {
                    if (temp->children[i]) que.push(temp->children[i]);
                }
            }
            res.push_back(data);
        }
        return res;
    }

填充每个节点的下一个右节点

每一层遍历的时候,前size - 1,指向next,最后一个置为nullptr。

    Node* connect(Node* root) {
        queue<Node*> que;
        if (root == nullptr) return nullptr;
      	que.push(root);
        while (!que.empty()) {
            int size = que.size();
            for (int i = 0; i < size; i++) {
                Node* temp = que.front();
                que.pop();
                if (i == size - 1) temp->next = nullptr;
                else temp->next = que.front();
                if (temp->left) que.push(temp->left);
                if (temp->right) que.push(temp->right);
            }
        }
        return root;
    }

填充每个节点的下一个右节点II

不要求是完美二叉树,同一层节点之间可以有空缺,和上一题一样。

二叉树的最大深度

每次while就是每一层。

    int maxDepth(TreeNode* root) {
        queue<TreeNode*> que;
        int cnt = 0;
        if (root == nullptr) return 0;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            for (int i = 0; i < size; i++) {
                TreeNode* temp = que.front();
                que.pop();
                if (temp->left) que.push(temp->left);
                if (temp->right) que.push(temp->right);
            }
            cnt++;
        }
        return cnt;
    }
	//DFS
    int max = INT_MIN;
    void doit(TreeNode* cur, int cnt) {
        if (cur == nullptr) return;
        cnt++;
        if (cnt > max) max = cnt;
        doit(cur->left, cnt);
        doit(cur->right, cnt);
    }
    int maxDepth(TreeNode* root) {
        if (root == nullptr) return 0;
        doit(root, 0);
        return max;
    }

二叉树的最小深度

当左右孩子都为空的时候,即遍历的最低点,对于层序那就是最低的,对于递归遍历那是有可能,要比较一下。

    int minDepth(TreeNode* root) {
        if (root == nullptr) return 0;
        queue<TreeNode*> que;
        int cnt = 0;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            while (size--) {
                TreeNode* temp = que.front();
                que.pop();
                if (temp->left == nullptr && temp->right == nullptr) return cnt + 1;
                if (temp->left) que.push(temp->left);
                if (temp->right) que.push(temp->right);
            }
            cnt++;
        }
        return cnt;
    }
	//DFS 
    int min = INT_MAX;
    void doit(TreeNode* cur, int cnt) {
        if (cur == nullptr) return;
        cnt++;
        if (cur->left == nullptr && cur->right == nullptr) min = cnt < min ? cnt : min;
        doit(cur->left, cnt);
        doit(cur->right, cnt);
    }
    int minDepth(TreeNode* root) {
        if (root == nullptr) return 0;
        doit(root, 0);
        return min;
    }

翻转二叉树

递归遍历前序和后序都可以,中序的话不太行,因为从左子树翻转完,中在反转一次会变成右子树,再翻转的是之前的左子树。

    TreeNode* invertTree(TreeNode* root) {
        Doit(root);
        return root;
    }
    void Doit(TreeNode* cur) {
        if (cur == nullptr) return;
        TreeNode* temp = cur->left;
        cur->left = cur->right;
        cur->right = temp;
        Doit(cur->left);
        Doit(cur->right);
    }

层序遍历也OK。

    TreeNode* invertTree(TreeNode* root) {
        queue<TreeNode*> que;
        if (root == nullptr) return root;
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            while (size--) {
                TreeNode* cur = que.front();
                que.pop();
                TreeNode* temp = cur->left;
                cur->left = cur->right;
                cur->right = temp;

                if (cur->left) que.push(cur->left);
                if (cur->right) que.push(cur->right);
            }
        }
        return root;
    }

迭代法,用栈存访问过的元素,指针来模拟迭代过程,前序。

    TreeNode* invertTree(TreeNode* root) {
        stack<TreeNode*> st;
        if (root == nullptr) return root;
        TreeNode* cur = root;
        while (!st.empty() || cur != nullptr) {
            if (cur) {
                st.push(cur);
                TreeNode* temp = cur->left;
                cur->left = cur->right;
                cur->right = temp;
                cur = cur->left;
            }
            else {
                cur = st.top();
                st.pop();
                cur = cur->right;
            }
        }
        return root;
    }

对称二叉树

递归的第一部思考递归参数和返回值也很重要,当只传一个参数不太好解决的时候,考虑考虑传两个参数,尤其是针对树类型,另外if else有时候else是必须的有时候是可以不要的,如果几个if之间的变量彼此独立,就可以不写else,否则如果第一个if执会影响第二个if里的量那就要加else。

  • 有一点要注意,这里点的对称指的是左右子树,而不是左右节点对称,是关于中轴线的对称。
  • 实际先左后右递归是后序,左子树左右中,右子树右左中。
    bool isSymmetric(TreeNode* root) {
        if (root == nullptr) return root;
        return doit(root->left, root->right);
    }
    bool doit(TreeNode* left, TreeNode* right) {
        if (left == nullptr && right == nullptr) return true;
        else if (left == nullptr && right != nullptr || left != nullptr && right == nullptr) return false;
        else if (left->val == right->val) {
            return doit(left->left, right->right) && doit(left->right, right->left);
        } else return false;
    }

迭代法使用队列,从root开始每次放一对left和right进队列,然后再弹出队首进行比较,注意这并不是层序遍历模板写法,但其实还是按每一层遍历的,由两边向中间搜索。

  • 使用队列的时候注意都为空是continue继续检查下一层节点而不是直接return true,和递归不一样,递归返回的时候已经后续遍历完一遍数组了,递归是通过下层返回的结果反向向上推,而层序遍历是向下遍历的时候就得到了结果。
    bool isSymmetric(TreeNode* root) {
        queue<TreeNode*> que;
        if (root == nullptr) return true;
        que.push(root->left);
        que.push(root->right);
        while (!que.empty()) {
            TreeNode* left = que.front(); que.pop();
            TreeNode* right = que.front(); que.pop();
            if (left == nullptr && right == nullptr) continue;
            else if (left != nullptr && right == nullptr || left == nullptr && right != nullptr) return false;
            else if (left->val == right->val) {
                que.push(left->left);
                que.push(right->right);
                que.push(left->right);
                que.push(right->left);
            } else return false;
        }
        return true;
    }

实际上有个容器来存储遍历的元素就可以了,遍历顺序与容器无关,所以栈或者数组也可以完成,以栈为例,和队列的区别就在于出去的元素是从头还是尾出了。

  • 栈由于先进后出的特性实际上是深度优先遍历,一条子树走到底,不过因为最后都会遍历完整棵树并且是对称问题,所以入栈是先左后右还是先右后左就无所谓了。
        stack<TreeNode*> que;
        if (root == nullptr) return true;
        que.push(root->right);
        que.push(root->left);
        while (!que.empty()) {
            TreeNode* left = que.top(); que.pop();
            TreeNode* right = que.top(); que.pop();
            if (left == nullptr && right == nullptr) continue;
            else if (left != nullptr && right == nullptr || left == nullptr && right != nullptr) return false;
            else if (left->val == right->val) {
                que.push(right->right);
                que.push(left->left);
                que.push(right->left);
                que.push(left->right);
            } else return false;
        }
        return true;
    }

相同的树 100

把比较的两棵树当两颗子树,只不过递归的时候左跟左比,右跟右比,而不是对称着比了,重点理解递归有两个参数的使用。5 min秒了,用递归写的。

class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        return Doit(p, q);
    }

    bool Doit(TreeNode* p, TreeNode* q) {
        if (p == nullptr && q == nullptr) return true;
        else if (p != nullptr && q == nullptr || p == nullptr && q != nullptr) return false;
        else if (p->val == q->val) {
            return Doit(p->left, q->left) && Doit(p->right, q->right);
        } else return false;
    }

};

另一颗的子树

套了两层递归,互相调用,三刷再看,是对称树的延伸