leetcode刷题 (8.26) 二叉树

二叉树可以链式存储,也可以顺序存储。

链式存储方式就用指针, 顺序存储的方式用数组。

二叉树链式存储定义

C++

struct TreeNode{
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x): val(x), left(NULL), right(NULL) {}
};

Python

class TreeNode:
	def __init__(self, value):
		self.value = value
		self.left = None
		self.right = None

1. 二叉树的递归遍历

递归算法分三步来写:

  • 确认递归函数的参数和返回值
  • 确认终止条件
  • 确认单层递归逻辑

(1)前序遍历

144

题目:给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

输入:root = [1,null,2,3]
输出:[1,2,3]

思路:前序:根——左——右

笔记:C++中push_back()函数用于在vector最后添加一个元素。

C++

class Solution {
public:
    void preorder(TreeNode *root, vector<int> &res){
        if (root == nullptr) return;
        res.push_back(root->val);
        preorder(root->left, res);
        preorder(root->right, res);
    }

    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> res;  //保存结果
        preorder(root, res);
        return res;
    }
};

Python

class Solution:
    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:

        # 保存的结果
        result = []

        def preorder(root: TreeNode):
            if root == None:
                return
            result.append(root.val)
            preorder(root.left)
            preorder(root.right)
        
        preorder(root)
        return result

(2)中序遍历

94

题目:给你二叉树的根节点 root ,返回它节点值的 中序 遍历。

输入:root = [1,null,2,3]
输出:[1,3,2]

思路:中序:左——根——右

C++

class Solution {
public:
    void inorder(TreeNode *root, vector<int> &res){
        if(root == nullptr) return;
        inorder(root->left, res);
        res.push_back(root->val);
        inorder(root->right, res);
    }

    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        inorder(root, res);
        return res;
    }
};

Python

class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:

        result = []

        def inorder(root: TreeNode):
            if root == None:
                return
            inorder(root.left)
            result.append(root.val)
            inorder(root.right)

        inorder(root)
        return result

(3)后序遍历

145

题目:给你二叉树的根节点 root ,返回它节点值的 后序 遍历。

输入:root = [1,null,2,3]
输出:[3,2,1]

思路:后序:左——右——根

C++

class Solution {
public:
    void postorder(TreeNode *root, vector<int> &res){
        if (root == nullptr) return;
        postorder(root->left, res);
        postorder(root->right, res);
        res.push_back(root->val);
    }

    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        postorder(root, res);
        return res;
    }
};

Python

class Solution:

    def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        result = []

        def postorder(root: TreeNode):
            if root == None:
                return
            postorder(root.left)
            postorder(root.right)
            result.append(root.val)

        postorder(root)
        return result

2. 二叉树的迭代遍历

后续补充…

3. 二叉树的迭代遍历

后续补充…

4. 二叉树的层序遍历

(1)经典层序遍历

102

题目:给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
leetcode刷题 (8.26) 二叉树_第1张图片

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]

思路:需要借用一个辅助队列来实现,队列先进先出,符合一层一层遍历的逻辑。

笔记:C++中que.front()函数返回队列的前端元素。
python中队列操作常采用from collections import deque,deque为双端队列。
其中,append()是从右端入队,popleft()是从左端移除

C++

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> que; //定义队列
        if(root != nullptr) que.push(root); //根入队
        vector<vector<int>> result;  //结果为二维数组
        while(!que.empty()){
            int size = que.size();

            // 内层数组:每一层的结点
            vector<int> res;
            // 用固定大小size,不要使用que.size(),因为que.size是不断变化的
            for(int i = 0; i < size; i++){
             	// 队头写到结果里
                TreeNode *node = que.front(); 
                que.pop();  
                // 队头写到结果里
                res.push_back(node->val);  
                // 再把他的左右孩子入队
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
            result.push_back(res); //每层res再写入外层数组中
        }
        return result;
    }
};

Python

class Solution:
    def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        results = []
        if root == None:
            return results

        from collections import deque
        # root入队
        que = deque([root])  

        while que:
            size = len(que)
            # 内层数组
            result = []
            for _ in range(size):
                # 弹出一个值作为node
                node = que.popleft()
                # node存入内层中
                result.append(node.val)
                # 把他的左右孩子入队
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
            results.append(result)
        return results

(2)从底向上层序遍历

107

题目:给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
leetcode刷题 (8.26) 二叉树_第2张图片

输入:root = [3,9,20,null,null,15,7]
输出:[[15,7],[9,20],[3]]

思路:就是把经典层序遍历最后的result数组反转一下即可

笔记

C++

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        queue<TreeNode*> que; //定义队列
        if(root != nullptr) que.push(root); //根入队
        vector<vector<int>> result;  //结果为二维数组
        while(!que.empty()){
            int size = que.size();

            // 内层数组:每一层的结点
            vector<int> res;
            // 用固定大小size,不要使用que.size(),因为que.size是不断变化的
            for(int i = 0; i < size; i++){
             	// 队头写到结果里
                TreeNode *node = que.front(); 
                que.pop();  
                // 队头写到结果里
                res.push_back(node->val);  
                // 再把他的左右孩子入队
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
            result.push_back(res); //每层res再写入外层数组中
        }
        // 反转数组
        reverse(result.begin(), result.end());
        return result;
    }
};

Python

class Solution:
    def levelOrderBottom(self, root: Optional[TreeNode]) -> List[List[int]]:
        results = []
        if root == None:
            return results

        from collections import deque
        # root入队
        que = deque([root])  

        while que:
            size = len(que)
            # 内层数组
            result = []
            for _ in range(size):
                # 弹出一个值作为node
                node = que.popleft()
                # node存入内层中
                result.append(node.val)
                # 把他的左右孩子入队
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
            results.append(result)

        results.reverse()
        return results

(3)二叉树的右视图

199

题目:给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
leetcode刷题 (8.26) 二叉树_第3张图片

输入: [1,2,3,null,5,null,4]
输出: [1,3,4]

思路:层序遍历的时候,判断是否遍历到单层的最后面的元素,如果是,就放进result数组中

for (int i = 0; i < size; i++) {
    TreeNode* node = que.front();
    que.pop();
    if (i == (size - 1)) result.push_back(node->val); // 将每一层的最后元素放入result数组中
    if (node->left) que.push(node->left);
    if (node->right) que.push(node->right);
}

(4)二叉树的层平均值

637

题目:给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。

输入:root = [3,9,20,null,null,15,7]
输出:[3.00000,14.50000,11.00000]
解释:第 0 层的平均值为 3,第 1 层的平均值为 14.5,第 2 层的平均值为 11 。
因此返回 [3, 14.5, 11]

思路:层序遍历的时候把一层求个总和在取一个均值。

C++

for (int i = 0; i < size; i++) {
	TreeNode* node = que.front();
	que.pop();
	sum += node->val;
	if (node->left) que.push(node->left);
	if (node->right) que.push(node->right);
}
result.push_back(sum / size); // 将每一层均值放进结果集

Python

while que:
    size = len(que)
    sum_ = 0
    for _ in range(size):
        cur = que.popleft()
        sum_ += cur.val
        if cur.left:
            que.append(cur.left)
        if cur.right:
            que.append(cur.right)
    results.append(sum_ / size)

(5)N叉树的层序遍历

429

题目:给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。
树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。
leetcode刷题 (8.26) 二叉树_第4张图片

输入:root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出:[[1],[2,3,4,5],[6,7,8,9,10],[11,12,13],[14]]

思路:左孩右孩变成children数组

笔记:Python:deque中extend()函数表示将一个list的值全部入队。

C++

for (int i = 0; i < size; i++) {
    Node* node = que.front();
    que.pop();
    vec.push_back(node->val);
    for (int i = 0; i < node->children.size(); i++) { // 将节点孩子加入队列
        if (node->children[i]) que.push(node->children[i]);
    }
}
result.push_back(vec);

Python

while que:
	result = []
	 for _ in range(len(que)):
	     cur = que.popleft()
	     result.append(cur.val)
	     # cur.children 是 Node 对象组成的列表,也可能为 None
	     if cur.children:
	         que.extend(cur.children)
	 results.append(result)

(6)在每个树行中找最大值

515

题目:给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。

输入: root = [1,3,2,5,3,null,9]
输出: [1,3,9]

思路:每层for循环中每次都比较最大值

笔记

C++

int maxValue = INT_MIN; // 取每一层的最大值
for (int i = 0; i < size; i++) {
    TreeNode* node = que.front();
    que.pop();
    maxValue = node->val > maxValue ? node->val : maxValue;
    if (node->left) que.push(node->left);
    if (node->right) que.push(node->right);
}
result.push_back(maxValue); // 把最大值放进数组

Python

while que:
    cur = -inf
    for _ in range(len(que)):
        node = que.popleft()
        cur = max(cur, node.val)
        if node.left:
            que.append(node.left)
        if node.right:
            que.append(node.right)
    results.append(cur)

(7)填充每个节点的下一个右侧节点指针

116

题目:给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。

初始状态下,所有 next 指针都被设置为 NULL。
leetcode刷题 (8.26) 二叉树_第5张图片

输入:root = [1,2,3,4,5,6,7]
输出:[1,#,2,3,#,4,5,6,7,#]
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化的输出按层序遍历排列,同一层节点由 next 指针连接,'#' 标志着每一层的结束。

思路

笔记

C++

class Solution {
public:
    Node* connect(Node* root) {
        queue<Node*> que;
        if (root != NULL) que.push(root);
        while (!que.empty()) {
            int size = que.size();
            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; // 前一个节点指向当前节点
                    nodePre = nodePre->next;   // 前一节点往后移
                }
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
            nodePre->next = NULL; // 本层最后一个节点指向NULL
        }
        return root;

    }
};

Python

迭代法

def connect(self, root: 'Node') -> 'Node':
    if not root:
        return 
    if root.left:
        root.left.next = root.right
        if root.next:
            root.right.next = root.next.left
    self.connect(root.left)
    self.connect(root.right)
    return root

层次遍历法

import collections 

class Solution:
    def connect(self, root: 'Node') -> 'Node':
        if not root:
            return root    
        # 初始化队列同时将第一层节点加入队列中,即根节点
        Q = collections.deque([root])
        # 外层的 while 循环迭代的是层数
        while Q:
            # 记录当前队列大小
            size = len(Q)
            # 遍历这一层的所有节点
            for i in range(size):
                # 从队首取出元素
                node = Q.popleft()
                # 连接
                if i < size - 1:   # size-1连的是NULL,不需要做处理
                    node.next = Q[0] #因为当前节点已经从队列中pop了,Q[0]即下一个节点
                # 拓展下一层节点
                if node.left:
                    Q.append(node.left)
                if node.right:
                    Q.append(node.right)   
        # 返回根节点
        return root

(8)二叉树的最大深度

104

题目:给定一个二叉树,找出其最大深度

思路return len(results)即可。

C++

class Solution {
public:
    int maxDepth(TreeNode* root) {
        if (root == NULL) return 0;
        int depth = 0;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()) {
            int size = que.size();
            depth++; // 记录深度
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        }
        return depth;
    }
};

Python

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        results = []
        if root == None:
            return len(results)

        from collections import deque
        # root入队
        que = deque([root])  

        while que:
            size = len(que)
            # 内层数组
            result = []
            for _ in range(size):
                # 弹出一个值作为node
                node = que.popleft()
                # node存入内层中
                result.append(node.val)
                # 把他的左右孩子入队
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
            results.append(result)
        return len(results)

(9)二叉树的最小深度

111

题目:给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

输入:root = [3,9,20,null,null,15,7]
输出:2

思路:和最大深度一样,只是判定条件为:左右孩都为空。

笔记

C++

class Solution {
public:
    int minDepth(TreeNode* root) {
        if (root == NULL) return 0;
        int depth = 0;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()) {
            int size = que.size();
            depth++; // 记录最小深度
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
                if (!node->left && !node->right) { // 当左右孩子都为空的时候,说明是最低点的一层了,退出
                    return depth;
                }
            }
        }
        return depth;
    }
};

Python

class Solution:
    def minDepth(self, root: Optional[TreeNode]) -> int:
        if root == None:
            return 0

        from collections import deque
        # root入队
        que = deque([root])  
        depth = 0

        while que:
            size = len(que)
            # 内层数组
            depth += 1
            for _ in range(size):
                # 弹出一个值作为node
                node = que.popleft()
                # 把他的左右孩子入队
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
                if node.left == None and node.right == None:
                    return depth

你可能感兴趣的:(leetcode刷题,leetcode,算法)