LeetCode 每周算法 5(二叉树)

LeetCode 每周算法 5(二叉树)

二叉树算法:

在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        WHITE, GRAY = 0, 1
        res = []
        stack = [(WHITE, root)]
        while stack:
            color, node = stack.pop()
            if node is None: continue
            if color == WHITE:
                stack.append((WHITE, node.right))
                stack.append((GRAY, node))
                stack.append((WHITE, node.left))
            else:
                res.append(node.val)
        return res

在这里插入图片描述

/**
 * 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 maxDepth(TreeNode* root) {
        // 首先检查根节点是否为nullptr  
        // 如果是nullptr,说明当前子树为空,因此最大深度为0  
        // 直接返回0,结束递归  
        if (root == nullptr) return 0;  
        // 如果根节点不为nullptr,则递归地计算左子树和右子树的最大深度  
        // maxDepth(root->left) 计算左子树的最大深度  
        // maxDepth(root->right) 计算右子树的最大深度  
        // 使用max函数比较这两个值,得到左右子树中较大的深度  
        // 然后将这个深度加1(加上根节点本身),得到当前子树的最大深度  
        // 最后返回这个值  
        return max(maxDepth(root->left), maxDepth(root->right)) + 1;
    }
};

在这里插入图片描述

/**
 * 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:
    TreeNode* invertTree(TreeNode* root) {
        // 检查根节点是否为nullptr
        if (root == nullptr) {
            return nullptr;
        }
        // 递归地反转左子树,并将反转后的左子树的根节点指针存储在left变量中  
        TreeNode* left = invertTree(root->left);  
        // 递归地反转右子树,并将反转后的右子树的根节点指针存储在right变量中  
        TreeNode* right = invertTree(root->right);  
        // 将当前节点的左子树指针指向原本右子树的位置(即反转后的右子树)  
        root->left = right;  
        // 将当前节点的右子树指针指向原本左子树的位置(即反转后的左子树)  
        root->right = left;  
        // 返回当前节点,此时它已经成为了反转后子树的根节点  
        return root;
    }
};

在这里插入图片描述

/**
 * 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:
    // 定义一个函数check,用于递归地检查两棵树p和q是否是对称的  
    // 对称意味着p的左子树与q的右子树结构相同且值相等,同时p的右子树与q的左子树也满足这一条件  
    bool check(TreeNode *p, TreeNode *q) {  
        // 如果两个节点都为空,则它们是对称的(因为都没有子树)  
        if (!p && !q) return true;  
        // 如果只有一个节点为空,则它们不是对称的  
        if (!p || !q) return false;  
        // 递归地检查p的左子树与q的右子树是否对称,以及p的右子树与q的左子树是否对称  
        // 如果这两对子树都对称,则p和q也是对称的  
        return p->val == q->val && check(p->left, q->right) && check(p->right, q->left);  
    }  
    
    // 定义一个函数isSymmetric,用于检查一棵二叉树root是否是对称的  
    // 实际上,对于一棵二叉树来说,要检查它是否对称,只需要检查它的根节点与根节点本身(看似无意义,但这里利用了check函数的特性)  
    // 这是因为如果整棵树是对称的,那么它的左子树和右子树就应该是镜像对称的  
    // 所以,我们将根节点作为两棵要比较的树的根传入check函数  
    bool isSymmetric(TreeNode* root) {  
        return check(root, root);
    }
};

在这里插入图片描述

/**
 * 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 {
    int diameter = 0; // 用于存储直径
public:
    int maxDepth(TreeNode* root) {
        if (root == NULL) {
            return 0; // 访问到空节点了,返回0
        }
        // 计算diameter即L+R+1 并更新diameter
        diameter = max(diameter, maxDepth(root->left) + maxDepth(root->right) + 1);
        // 返回该节点为根的子树的深度
        return max(maxDepth(root->left), maxDepth(root->right)) + 1;
    }
    int diameterOfBinaryTree(TreeNode* root) {
        maxDepth(root);
        return diameter - 1;
    }
};

在这里插入图片描述

/**
 * 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:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector <vector<int>> result; // 用于存储结果的二维向量
        if (!root) { // 如果根节点为空,则直接返回空的结果
            return result;
        }

        queue <TreeNode*> queue; // 使用队列来辅助层序遍历  
        queue.push(root); // 将根节点入队

        while (!queue.empty()) { // 当队列不为空时,继续遍历
            int currentLevelSize = queue.size(); // 当前层的节点数
            result.push_back(vector <int> ()); // 为当前层创建一个新的向量来存储节点值

            for (int i = 1; i <= currentLevelSize; ++i) { // 遍历当前层的所有节点
                auto node = queue.front(); queue.pop(); // 取出队列前端的节点,并从队列中移除
                result.back().push_back(node->val); // 将节点值添加到当前层的向量中

                // 如果当前节点有左子节点,则将左子节点入队
                if (node->left) queue.push(node->left);
                // 如果当前节点有右子节点,则将右子节点入队
                if (node->right) queue.push(node->right);
            }
        }

        return result; // 返回存储了所有层节点值的二维向量
    }
};

在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
        def helper(left, right):
            # 基本情况:如果左边界大于右边界,说明当前子数组为空,返回None作为空树  
            if left > right:  
                return None  
            
            # 计算中间索引,这里使用了整数除法,以确保结果为整数  
            mid = (left + right) // 2  
            
            # 创建一个新的树节点,其值为中间元素的值  
            # 注意:这里假设`nums`是一个在函数外部定义的有序数组  
            root = TreeNode(nums[mid])  
            
            # 递归构建左子树,范围是左边界到中间索引的前一个位置  
            root.left = helper(left, mid - 1)  
            
            # 递归构建右子树,范围是中间索引的后一个位置到右边界  
            root.right = helper(mid + 1, right)  
            
            # 返回构建好的当前子树的根节点  
            return root

在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    # 定义一个辅助函数,用于递归地检查BST的有效性  
    # node是当前检查的节点,lower是该节点允许的最小值(初始为负无穷大),upper是该节点允许的最大值(初始为正无穷大)  
    def isValidBST(self, root: TreeNode) -> bool:
        def helper(node, lower=float('-inf'), upper=float('inf')) -> bool:  
            # 如果当前节点为空,则认为是有效的BST(空树也是BST)  
            if not node:  
                return True  
    
            # 获取当前节点的值  
            val = node.val  
            # 如果当前节点的值不满足其应在的范围内(即小于等于下限或大于等于上限),则不是有效的BST  
            if val <= lower or val >= upper:  
                return False  
    
            # 递归检查右子树,右子树的所有节点的值应大于当前节点的值且小于上限  
            if not helper(node.right, val, upper):  
                return False  
            # 递归检查左子树,左子树的所有节点的值应小于当前节点的值且大于等于下限  
            if not helper(node.left, lower, val):  
                return False  
            # 如果以上检查都通过,则当前子树是有效的BST  
            return True  
            
        # 调用辅助函数开始检查整棵树  
        return helper(root)

在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
        # 初始化一个空栈用于存储遍历过程中的节点  
        stack = []  
        
        # 当根节点不为空或栈不为空时,继续循环  
        while root or stack:  
            # 尽可能地向左子树深入,将沿途的节点推入栈中  
            while root:  
                stack.append(root)  # 将当前节点推入栈中  
                root = root.left    # 移动到左子节点  
            
            # 弹出栈顶元素(即当前子树中最左边的节点)  
            root = stack.pop()  
            
            # 将计数器k减1,因为我们找到了一个元素  
            k -= 1  
            
            # 如果计数器k减至0,说明找到了第k小的元素  
            if k == 0:  
                return root.val  # 返回该元素的值  
            
            # 否则,继续遍历右子树  
            root = root.right    # 移动到右子节点

在这里插入图片描述

/**
 * 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:
    vector<int> rightSideView(TreeNode* root) {
        vector<int> ans; // 用于存储每一层最右边的节点值
        if (!root) return ans; // 如果根节点为空,则直接返回空向量

        queue<TreeNode*> q; // 使用队列进行层序遍历 
        q.push(root); // 将根节点加入队列

        while (!q.empty()) { // 当队列不为空时,继续遍历
            int cnt = q.size(); // 当前层的节点数
            for (int i = 0; i < cnt; i++) { // 遍历当前层的所有节点
                TreeNode* cur = q.front(); q.pop(); // 取出队列的第一个节点,即当前层的某个节点
                if (cur->left) q.push(cur->left); // 如果当前节点的左子节点存在,将其加入队列
                if (cur->right) q.push(cur->right); // 如果当前节点的右子节点存在,将其加入队列
                if (i == cnt - 1) { // 当遍历到当前层的最后一个节点时,将其值加入答案向量
                    ans.push_back(cur->val);
                } 
            }
        }
        return ans; // 返回存储了每一层最右边节点值的向量
    }
};

在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def flatten(self, root: Optional[TreeNode]) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        # 初始化一个空列表,用于存储前序遍历的结果  
        preorderList = list()  
        
        # 定义前序遍历的函数  
        def preorderTraversal(root: TreeNode):  
            if root:  # 如果当前节点不为空  
                preorderList.append(root)  # 将当前节点添加到列表中  
                preorderTraversal(root.left)  # 递归遍历左子树  
                preorderTraversal(root.right)  # 递归遍历右子树  
        
        # 调用前序遍历函数,传入根节点  
        preorderTraversal(root)  
        
        # 获取前序遍历结果列表的长度  
        size = len(preorderList)  
        
        # 遍历前序遍历结果列表(从第二个元素开始,即索引为1的元素)  
        for i in range(1, size):  
            prev, curr = preorderList[i - 1], preorderList[i]  # 分别获取前一个节点和当前节点  
            prev.left = None  # 将前一个节点的左子节点设置为None  
            prev.right = curr  # 将前一个节点的右子节点设置为当前节点

在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:  
        # 定义一个内部函数,用于递归地构建二叉树  
        def myBuildTree(preorder_left: int, preorder_right: int, inorder_left: int, inorder_right: int):  
            # 如果前序遍历的索引范围无效(即左边界大于右边界),则返回None,表示该子树为空  
            if preorder_left > preorder_right:  
                return None  
              
            # 前序遍历的第一个元素(当前递归层级的起始索引)是根节点  
            preorder_root = preorder_left  
            # 在中序遍历中找到根节点的索引  
            inorder_root = index[preorder[preorder_root]]  
            
            # 创建一个新的TreeNode对象作为根节点  
            root = TreeNode(preorder[preorder_root])  
            # 计算左子树的大小(即中序遍历中根节点左侧的元素数量)  
            size_left_subtree = inorder_root - inorder_left  
            # 递归构建左子树,并更新前序遍历和中序遍历的索引范围  
            root.left = myBuildTree(preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1)  
            # 递归构建右子树,并更新前序遍历和中序遍历的索引范围  
            root.right = myBuildTree(preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right)  
            # 返回构建好的子树的根节点  
            return root  
  
        # 获取前序遍历列表的长度  
        n = len(preorder)  
        # 创建一个字典,用于将中序遍历中的每个元素映射到其索引  
        index = {element: i for i, element in enumerate(inorder)}  
        # 调用内部函数来构建整棵树,传入前序遍历和中序遍历的完整索引范围  
        return myBuildTree(0, n - 1, 0, n - 1)

在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int:  
        # 使用 defaultdict 初始化 prefix 字典
        # 默认值为 0,用于记录从根到当前节点的路径和出现的次数  
        prefix = defaultdict(int)  
        # 初始化 prefix[0] 为 1,表示路径和为 0 的情况
        #(即不选择任何节点)有 1 种情况(即空路径)  
        prefix[0] = 1  
  
        def dfs(root, curr):  
            # 如果当前节点为空,则没有路径可以遍历,返回 0  
            if not root:  
                return 0  
  
            # 初始化当前路径上找到的目标路径数  
            ret = 0  
            # 将当前节点的值加到当前路径和 curr 上  
            curr += root.val  
            # 如果当前路径和减去目标值 targetSum 在 prefix 中存在
            # 则说明之前有一条路径的和加上当前节点的值等于 targetSum  
            # 因此,我们将这样的路径数加到 ret 中  
            ret += prefix[curr - targetSum]  
            # 更新 prefix 字典,表示当前路径和 curr 出现的次数加 1  
            prefix[curr] += 1  
            # 递归遍历左子树和右子树,并将返回的路径数加到 ret 中  
            ret += dfs(root.left, curr)  
            ret += dfs(root.right, curr)  
            # 回溯,将当前路径和 curr 的出现次数减 1,以供后续路径使用  
            prefix[curr] -= 1  
  
            # 返回当前节点为根的子树中满足条件的路径总数  
            return ret

在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        # 定义一个内部的DFS函数,用于递归地搜索最低公共祖先  
        def dfs(root):  
            # 如果当前节点为空,或者当前节点就是我们要找的节点p或q,则返回当前节点  
            if not root or root.val in [p.val, q.val]:  
                return root  
            # 否则,递归地在左子树中搜索p和q  
            left = dfs(root.left)  
            # 递归地在右子树中搜索p和q  
            right = dfs(root.right)  
            # 如果左子树和右子树都返回了非空节点,说明p和q分别位于当前节点的左右子树中  
            # 因此,当前节点就是p和q的最低公共祖先  
            if left and right:  
                return root  
            # 如果左子树返回了非空节点而右子树没有,说明p和q都在左子树中  
            # 或者其中一个在左子树中,另一个是当前节点(但这种情况已在开头处理)  
            # 因此,返回左子树中的结果  
            elif left:  
                return left  
            # 同理,如果右子树返回了非空节点而左子树没有,返回右子树中的结果  
            elif right:  
                return right  
            # 如果左右子树都没有返回结果(理论上不会发生,除非树的结构有问题或p, q不在树中)  
            # 但这里为了代码的完整性,我们仍然保留了这个分支  
  
        # 调用DFS函数,从根节点开始搜索  
        return dfs(root)

在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def __init__(self):  
        # 初始化一个变量来存储找到的最大路径和,初始化为负无穷大  
        self.maxSum = float("-inf")  
  
    def maxPathSum(self, root: Optional[TreeNode]) -> int:  
        # 定义一个内部递归函数maxGain,用于计算以当前节点为根的子树中,经过当前节点的最大路径和  
        # 同时,这个函数也会更新全局的maxSum  
        def maxGain(node):  
            # 如果当前节点为空,则没有路径和,返回0  
            if not node:  
                return 0  
  
            # 递归计算左子树和右子树经过各自根节点的最大增益
            #(即最大路径和的一部分,但不包括当前节点)  
            # 如果增益为负,则视为0,因为负增益对路径和没有贡献  
            leftGain = max(maxGain(node.left), 0)  
            rightGain = max(maxGain(node.right), 0)  
  
            # 计算经过当前节点的路径和(包括当前节点值、左子树增益和右子树增益)  
            priceNewpath = node.val + leftGain + rightGain  
  
            # 更新全局的最大路径和  
            self.maxSum = max(self.maxSum, priceNewpath)  
  
            # 返回以当前节点为根的子树中,经过当前节点的最大单路径和(不包括其他分支)  
            # 这意味着我们只考虑当前节点、左子树的最大增益或右子树的最大增益中的较大者  
            return node.val + max(leftGain, rightGain)  
  
        # 从根节点开始调用maxGain函数,计算最大路径和  
        maxGain(root)  
        # 返回计算得到的最大路径和  
        return self.maxSum
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值