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. 二叉树的迭代遍历

因为递归可以用过栈来实现:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。

(1)前序遍历

在这里插入图片描述
C++

在这里插入代码片

Python

class Solution:
    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        result = []
        if not root:
            return result
        stack = [root]

        while stack:
            node = stack.pop()
            result.append(node.val)
            if node.right:
                stack.append(node.right)
            if node.left:
                stack.append(node.left)
        return result
(2)后序遍历

在这里插入图片描述

C++

在这里插入代码片

Python

class Solution:
    def postorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        stack = [root]
        result = []
        while stack:
            node = stack.pop()
            # 中结点先处理
            result.append(node.val)
            # 左孩子先入栈
            if node.left:
                stack.append(node.left)
            # 右孩子后入栈
            if node.right:
                stack.append(node.right)
        # 将最终的数组翻转
        return result[::-1]
(3)中序遍历

中序对于先序和后序要复杂一点,因为先序的访问顺序和输出顺序是一致的,访问一个就可以输出,再丢弃。因为二叉树的代码都是从顶端开始访问的,但是中序是左-中-右,就意味着要先从顶部找到左边最低端,再开始从左向上输出,所以需要一个指针来帮助遍历结点。

C++

在这里插入代码片

Python

class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        stack = []  # 不能提前将root结点加入stack中
        result = []
        cur = root
        while cur or stack:
            # 用来把自顶向左的访问顺序的路径存在stack中,栈顶就是最左结点
            if cur:     
                stack.append(cur)
                cur = cur.left		
            # 从最左结点开始处理输出   
            else:		
                cur = stack.pop()
                result.append(cur.val)
                # 取栈顶元素右结点
                cur = cur.right	
        return result

3. 二叉树的层序遍历

(1)经典层序遍历

102

题目:给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
在这里插入图片描述

输入: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])  

		# 每次pop出来一个节点,就把其子女入que,所以当子女都没子女了,就终结
        while que:
            size = len(que)  #这里的size只是每层的结点数量,会更新
            # 内层数组
            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 ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
在这里插入图片描述

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

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

笔记
Python中reverse()reversed()的区别:
reverse()仅限于list,返回值是None,结果可以直接print出来

a1=[1,2,3,4]
print(a1.reverse())
print(a1)
None
[4, 3, 2, 1]

reversed()可用于tuple, string, list 或 range,返回值是一个迭代器,结果需要通过列表、元组或者for循环输出

a1=[1,2,3,4]
print(reversed(a1))
print(list(reversed(a1)))
<list_reverseiterator object at 0x0000023F56ACD4C0>
[4, 3, 2, 1]
# 字符串
seqString = 'Runoob'
print(list(reversed(seqString)))
 
# 元组
seqTuple = ('R', 'u', 'n', 'o', 'o', 'b')
print(list(reversed(seqTuple)))
 
# range
seqRange = range(5, 9)
print(list(reversed(seqRange)))
 
# 列表
seqList = [1, 2, 4, 3, 5]
print(list(reversed(seqList)))

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,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
在这里插入图片描述

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

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

C++

class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        vector<int> res;
        queue<TreeNode*> que;
        if(root == NULL) return res;
        que.push(root);
        while(!que.empty()){
            int size = que.size();
            TreeNode* node = que.back();
            res.push_back(node->val);
            for(int i = 0; i < size; i++){
                node = que.front();
                que.pop();
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
        }
        return res;
    }
};

Python

from collections import deque

class Solution:
    def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
        res = []
        if not root:
            return res
        
        que = deque([root])

        while que:
            node = que[-1]
            res.append(node.val)

            for _ in range(len(que)):
                node = que.popleft()
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
                
        return res

(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++

class Solution {
public:
    vector<double> averageOfLevels(TreeNode* root) {
        vector<double> res;
        queue<TreeNode*> que;
        if(root == NULL) return res;

        que.push(root);
        while(!que.empty()){
            double sum_ = 0;
            int size = que.size();

            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);
            }
            res.push_back(sum_/size);
        }
        return res;
    }
};

Python

class Solution:
    def averageOfLevels(self, root: Optional[TreeNode]) -> List[float]:
        res = []
        if not root:
            return res
        
        from collections import deque

        que = deque([root])

        while que:
            size = len(que)
            sum_ = 0
            for _ in range(size):
                node = que.popleft()
                sum_ += node.val
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
            res.append(sum_/size)
        return res
(5)N叉树的层序遍历

429

题目:给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。
树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。
在这里插入图片描述

输入: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++

class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) {
        queue<Node*> que;
        vector<vector<int>> results;
        if(root == nullptr) return results;
        que.push(root);

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

Python

class Solution:
    def levelOrder(self, root: 'Node') -> List[List[int]]:
        results = []
        if not root:
            return results
        from collections import deque

        que = deque([root])

        while que:
            size = len(que)
            res = []
            for _ in  range(size):
                node = que.popleft()
                res.append(node.val)
                if node.children:
                    que.extend(node.children)
                
            results.append(res)
        return results
(6)在每个树行中找最大值

515

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

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

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

笔记

C++

class Solution {
public:
    vector<int> largestValues(TreeNode* root) {
        vector<int> res;
        queue<TreeNode*> que;
        if(root == NULL) return res;

        que.push(root);
        while (!que.empty()){
            int size = que.size();
            int max_ = INT_MIN;
            for(int i = 0; i < size; i++){
                TreeNode* node = que.front();
                que.pop();
                max_ = node->val > max_ ? node->val : max_;
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
            res.push_back(max_);
        }
        return res;
    }
};

Python

class Solution:
    def largestValues(self, root: Optional[TreeNode]) -> List[int]:
        res = []
        if root == None:
            return res
        from collections import deque

        que = deque([root])

        while que:
            max_ = -inf
            for _ in range(len(que)):
                node = que.popleft()
                max_ = max(max_, node.val)
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
            res.append(max_)
        return res
(7)填充每个节点的下一个右侧节点指针

116

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

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

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

初始状态下,所有 next 指针都被设置为 NULL。
在这里插入图片描述

输入: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) {
        if(root == nullptr) return root;
        queue<Node*> que;

        que.push(root);

        while (!que.empty()){
            int size = que.size();
            for(int i = 0; i < size; i++){
                Node* node = que.front();
                que.pop();

                if(i < size - 1){
                    node->next = que.front();
                }
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
        }
        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

层次遍历法

class Solution:
    def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
        if not root:
            return root
        from collections import deque
        que = deque([root])

        while que:
            size = len(que)
            for i in range(size):
                node = que.popleft()
                # 把这层中除了最右边的那个节点,其他节点全部next连起来
                # 放在第一个if,因为后面que会加孩子,就不只是这层的元素了
                if i < size - 1:
                    node.next = que[0]
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
        return root
(8)二叉树的最大深度

104

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

思路return len(results)即可。

C++

class Solution {
public:
    int maxDepth(TreeNode* root) {
        vector<vector<int>> results;
        queue<TreeNode*> que;
        if(root == NULL) return 0;

        que.push(root);
        while (!que.empty()){
            vector<int> res;
            int 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);
            }
            results.push_back(res);
        }
        return results.size();
    }
};

Python

class Solution:
    def maxDepth(self, root: Optional[TreeNode]) -> int:
        results = []

        if not root:
            return 0
        
        from collections import deque

        que = deque([root])

        while que:
            res = []
            for _ in range(len(que)):
                node = que.popleft()
                res.append(node.val)
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
            results.append(res)  
        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

  1. 迭代法(层序遍历)
class Solution:
    def minDepth(self, root: Optional[TreeNode]) -> int:
        if root == None:
            return 0
        
        from collections import deque

        que = deque([root])
        depth = 0

        while que:
            depth += 1
            for _ in range(len(que)):
                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
  1. 递归法
class Solution:
    def minDepth(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0
        if not root.left and not root.right:
            return 1

        min_depth = inf
        if root.left:
            min_depth = min(self.minDepth(root.left), min_depth)
        if root.right:
            min_depth = min(self.minDepth(root.right), min_depth)
        return min_depth + 1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值