【leetcode真题】二叉树和递归

本文探讨了二叉树的递归算法,包括求最大深度、最低深度、反转二叉树、判断是否是对称树、求节点数目、判断是否是平衡二叉树、路径和等问题,展示了递归在解决二叉树问题中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉树和递归:

递归,是使用计算机解决问题的一种重要的思考方式。而二叉树由于其天然的递归结构,使得基于二叉树的算法,均拥有着递归性质。使用二叉树,是研究学习递归算法的最佳入门方式。在这一章里,我们就来看一看二叉树中的递归算法。

二叉树天然的递归结构

问题1:Maximum Depth of Binary Tree(求最大深度)

原题

/// Recursive
/// Time Complexity: O(n), where n is the nodes' number in the tree
/// Space Complexity: O(h), where h is the height of the tree
class Solution {
public:
    int maxDepth(TreeNode* root) {

        if(root == NULL)
            return 0;

        return 1 + max(maxDepth(root->left), maxDepth(root->right));
    }
};
问题2: Minimum Depth of Binary Tree(最低深度)

原题

/// Recursive
/// Time Complexity: O(n)
/// Space Complexity: O(h)
class Solution {
public:
    int minDepth(TreeNode* root) {

        if(root == NULL)
            return 0;

        if(root->left == NULL && root->right == NULL)
            return 1;

        int ret = INT_MAX;
        if(root->left != NULL)
            ret = min(ret, 1 + minDepth(root->left));
        if(root->right != NULL)
            ret = min(ret, 1 + minDepth(root->right));
        return ret;
    }
};
问题3:Invert Binary Tree(反转二叉树)

原题

/// Recursive
/// Time Complexity: O(n), where n is the node's number of the tree
/// Space Complexity: O(h), where h is the height of the tree
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {

        if(root == NULL)
            return NULL;

        invertTree(root->left);
        invertTree(root->right);
        swap(root->left, root->right);

        return root;
    }
};
问题4:Symmetric Tree(判断是否是对称树)

原题

/// Recursive
/// No need to revert one child tree
/// See if the two child trees of the root are mirror directly
///
/// Time Complexity: O(n)
/// Space Complexity: O(h)
class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if (root == NULL){
            return true;
        }
        return is_mirror(root, root);
    }

private:
    bool is_mirror(TreeNode* root1, TreeNode* root2){
        if (root1 == NULL && root2 == NULL){
            return true;
        }
        if (root1 == NULL || root2 == NULL){
            return false;
        }
        if (root1->val != root2->val){
            return false;
        }
        return is_mirror(root1->left,root2->right) && is_mirror(root1->right, root2->left);
    }
};
问题5:Symmetric Tree(判断是否是对称树)

原题
Given a complete binary tree, count the number of nodes.
求完全二叉树的节点数目。注意完全二叉树和满二叉树Full Binary Tree的唯一区别是,完全二叉树最后一层的节点不满,而且假设最后一层有节点,都是从左边开始。 这样我们可以利用这个性质得到下面两个结论:

  1. 假如左子树高度等于右子树高度,则右子树为完全二叉树,左子树为满二叉树。
  2. 假如高度不等,则左字数为完全二叉树,右子树为满二叉树。
  3. 求高度的时候只往左子树来找。
/// Recursion
/// Time Complexity: O(h^2) where h is the height of the tree
/// Space Complexity: O(h)
class Solution {

public:
    int countNodes(TreeNode* root) {

        if(root == NULL)
            return 0;

        int leftLeft = leftHeight(root->left);
        int leftRight = rightHeight(root->left);
        if(leftLeft == leftRight)
            return 1 + ((1<<leftLeft) - 1) + countNodes(root->right);

        assert(leftLeft == leftRight + 1);
        return 1 + ((1<<rightRight) - 1) + countNodes(root->left);
    }

private:
    int leftHeight(TreeNode* root){
        if(root == NULL)
            return 0;
        return 1 + leftHeight(root->left);
    }

    int rightHeight(TreeNode* root){
        if(root == NULL)
            return 0;
        return 1 + rightHeight(root->right);
    }
};
问题5:Balanced Binary Tree(判断是否是平衡二叉树)

求二叉树是否平衡,根据题目中的定义,高度平衡二叉树是每一个结点的两个子树的深度差不能超过1,那么我们肯定需要一个求各个点深度的函数,然后对每个节点的两个子树来比较深度差,时间复杂度为O(NlgN),代码如下:

class Solution {
public:
    bool isBalanced(TreeNode *root) {
        if (!root) return true;
        if (abs(getDepth(root->left) - getDepth(root->right)) > 1) return false;
        return isBalanced(root->left) && isBalanced(root->right);    
    }
    int getDepth(TreeNode *root) {
        if (!root) return 0;
        return 1 + max(getDepth(root->left), getDepth(root->right));
    }
};

上面那个方法正确但不是很高效,因为每一个点都会被上面的点计算深度时访问一次,我们可以进行优化。方法是如果我们发现子树不平衡,则不计算具体的深度,而是直接返回-1。那么优化后的方法为:对于每一个节点,我们通过checkDepth方法递归获得左右子树的深度,如果子树是平衡的,则返回真实的深度,若不平衡,直接返回-1,此方法时间复杂度O(N),空间复杂度O(H),参见代码如下:

class Solution {
public:    
    bool isBalanced(TreeNode *root) {
        if (checkDepth(root) == -1) return false;
        else return true;
    }
    int checkDepth(TreeNode *root) {
        if (!root) return 0;
        int left = checkDepth(root->left);
        if (left == -1) return -1;
        int right = checkDepth(root->right);
        if (right == -1) return -1;
        int diff = abs(left - right);
        if (diff > 1) return -1;
        else return 1 + max(left, right);
    }
};
问题6:Path Sum

Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
Note: A leaf is a node with no children.
Example:
Given the below binary tree and sum = 22,

      5
     / \
    4   8
   /   / \
  11  13  4
 /  \      \
7    2      1

return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.

/// Recursive
/// Time Complexity: O(n), where n is the nodes' number of the tree
/// Space Complexity: O(h), where h is the height of the tree
class Solution {
public:
    bool hasPathSum(TreeNode* root, int sum) {
        if (!root){
            return false;
        }
        if (root->left == NULL && root->right == NULL){
            return sum == root->val;
        }
        return hasPathSum(root->left, sum-root->val) || hasPathSum(root->right,sum-root->val);
    }
};
问题6:Sum of Left Leaves

Find the sum of all left leaves in a given binary tree.
Example:

    3
   / \
  9  20
    /  \
   15   7

There are two left leaves in the binary tree, with values 9 and 15 respectively. Return 24.

这道题让我们求一棵二叉树的所有左子叶的和,那么看到这道题我们知道这肯定是考二叉树的遍历问题,那么最简洁的写法肯定是用递归,由于我们只需要累加左子叶之和,那么我们在进入递归函数的时候需要知道当前结点是否是左子节点,如果是左子节点,而且该左子节点再没有子节点了说明其是左子叶,那么我们将其值加入结果res中,我们用一个bool型的变量,如果为true说明当前结点是左子节点,若为false则说明是右子节点,不做特殊处理,整个来说就是个递归的先序遍历的写法,参见代码如下:

/// Recursion
/// Time Complexity: O(n)
/// Space Complexity: O(h)

/// Definition for a binary tree node.
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};


class Solution {

private:
    int res = 0;

public:
    int sumOfLeftLeaves(TreeNode* root) {

        if(!root) return 0;

        dfs(root, false);
        return res;
    }

private:
    void dfs(TreeNode* node, bool isLeft){

        if(!node->left && !node->right){
            if(isLeft) res += node->val;
            return;
        }

        if(node->left) dfs(node->left, true);
        if(node->right) dfs(node->right, false);
    }
};
问题7:Binary Tree Paths

原题

/// Recursive
/// Time Complexity: O(n), where n is the node's number in the tree
/// Space Complexity: O(h), where h is the height of the tree
class Solution {
public:
    vector<string> binaryTreePaths(TreeNode* root) {

        vector<string> res;

        //递归的终止条件
        if(root == NULL)
            return res;

        //只有根节点
        if(root->left == NULL && root->right == NULL){
            res.push_back(to_string(root->val));
            return res;
        }

        vector<string> leftPaths = binaryTreePaths(root->left);//获得左子树所有路径
        for(int i = 0 ; i < leftPaths.size() ; i ++)
            res.push_back(to_string(root->val) + "->" + leftPaths[i]);

        vector<string> rightPaths = binaryTreePaths(root->right);//得右子树所有路径
        for(int i = 0 ; i < rightPaths.size() ; i ++)
            res.push_back(to_string(root->val) + "->" + rightPaths[i]);

        return res;
    }
};
问题8:Path Sum II

原题
Given a binary tree and a sum, find all root-to-leaf paths where each path’s sum equals the given sum.
Note: A leaf is a node with no children.
Example:
Given the below binary tree and sum = 22,

      5
     / \
    4   8
   /   / \
  11  13  4
 /  \    / \
7    2  5   1


Return:
[
[5,4,11,2],
[5,8,4,5]
]

class Solution {

public:
    vector<vector<int>> pathSum(TreeNode* root, int sum) {

        vector<vector<int>> res;
        if(!root)
            return res;

        vector<int> tres;
        dfs(root, tres, 0, sum, res);
        return res;
    }

private:
    /**
     *进行深度优先遍历
     * @param node 当前节点
     * @param tres 把路径保存到这
     * @param tsum 临时和,用来判断找到的路径的和是否和总和相同
     * @param sum  总和(已知)
     * @param res   所有路径保存到这
     */
    void dfs(TreeNode* node, vector<int>& tres, int tsum,
             int sum, vector<vector<int>>& res){

        tres.push_back(node->val);
        tsum += node->val;

        //只有根节点的时候或者是已经没有子结点,就是已经遍历完了
        if(!node->left && !node->right){
            if(tsum == sum)
                res.push_back(tres);
        }
        else {
            if (node->left)
                dfs(node->left, tres, tsum, sum, res);

            if (node->right)
                dfs(node->right, tres, tsum, sum, res);
        }

        //把tres容器里面的元素删除
        tres.pop_back();
        return;
    }
};
问题9:Sum Root to Leaf Numbers

Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number.
An example is the root-to-leaf path 1->2->3 which represents the number 123.
Find the total sum of all root-to-leaf numbers.
Note: A leaf is a node with no children.

Example:

Input: [1,2,3]
    1
   / \
  2   3
Output: 25
Explanation:
The root-to-leaf path 1->2 represents the number 12.
The root-to-leaf path 1->3 represents the number 13.
Therefore, sum = 12 + 13 = 25.
class Solution {
public:
    int sumNumbers(TreeNode* root) {

        if(!root) return 0;

        int res = 0;
        dfs(root, 0, res);
        return res;
    }

private:
    void dfs(TreeNode* node, int tnum, int& sum){

        //把新的结点*10倍再加上原来的结点
        tnum = tnum * 10 + node->val;

        if(!node->left && !node->right)
            sum += tnum;
        else{
            if(node->left)
                dfs(node->left, tnum, sum);
            if(node->right)
                dfs(node->right, tnum, sum);
        }
    }
};
问题10:Path Sum III

You are given a binary tree in which each node contains an integer value.
Find the number of paths that sum to a given value.
The path does not need to start or end at the root or a leaf, but it must go downwards
(traveling only from parent nodes to child nodes).
The tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000.

Example:
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8

      10
     /  \
    5   -3
   / \    \
  3   2   11
 / \   \
3  -2   1

Return 3. The paths that sum to 8 are:

1.  5 -> 3
2.  5 -> 2 -> 1
3. -3 -> 11
/// Recursive
/// Time Complexity: O(n), where n is the node's number of the tree
/// Space Complexity: O(h), where h is the height of the tree
class Solution {

public:
    /**
     * 以root为根节点的二叉树中,寻找和为sum的路径
     * @param root
     * @param sum
     * @return 这样的路径的个数
     */
    int pathSum(TreeNode* root, int sum) {

        if(root == NULL)
            return 0;

        return findPath(root, sum)  //寻找包含root结点的路径
                + pathSum(root->left , sum)   //在node的左右结点中寻找不包含root
                + pathSum(root->right , sum);
    }

private:
    /**
     * 在以node为根节点的二叉树中,寻找包含node的路径,和为sum
     * @param node
     * @param num
     * @return 这样的路径个数
     */
    int findPath(TreeNode* node, int num){

        if(node == NULL)
            return 0;

        int res = 0;
        //不能直接返回1,如果有负数就不一样了
        if(node->val == num)
            res += 1;

        //node在此路径上
        res += findPath(node->left , num - node->val);
        res += findPath(node->right , num - node->val);

        return res;
    }
};
问题11:Lowest Common Ancestor of a Binary Search Tree

原题
Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”
Given binary search tree: root = [6,2,8,0,4,7,9,null,null,3,5]

在这里插入图片描述
Example 1:
Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
Output: 6
Explanation: The LCA of nodes 2 and 8 is 6.
Example 2:
Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
Output: 2
Explanation: The LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.

/// Recursive
/// Time Complexity: O(lgn), where n is the node's number of the tree
/// Space Complexity: O(h), where h is the height of the tree
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {

        assert(p && q);

        if(!root) return root;

        if(p->val < root->val && q->val < root->val)
            return lowestCommonAncestor(root->left, p, q);
        if(p->val > root->val && q->val > root->val)
            return lowestCommonAncestor(root->right, p, q);


        assert(p->val == root->val || q->val == root->val
                || (root->val - p->val) * (root->val - q->val) < 0);

        return root;
    }
};
问题13:Validate Binary Search Tree(判断是否是二分搜索树)

原题

/// Using inOrder traverse
/// Store all elements in an vector
///
/// Time Complexity: O(n)
/// Space Complexity: O(n)
class Solution {
public:
    bool isValidBST(TreeNode* root) {

        vector<int> vec;
        //中序遍历
        inOrder(root, vec);
        for(int i = 1 ; i < vec.size() ; i ++)
            //二分搜索树的定义
            if(vec[i-1] >= vec[i])
                return false;
        return true;
    }

private:
    void inOrder(TreeNode* node, vector<int>& vec){

        if(node == NULL)
            return;

        inOrder(node->left, vec);
        vec.push_back(node->val);
        inOrder(node->right, vec);
    }
};
问题14:Delete Node in a BST(删除二分查找树的一个结点)

原题
递归的解法,首先判断根节点是否为空。由于 BST 的左<根<右的性质,使得可以快速定位到要删除的结点,对于当前结点值不等于 key 的情况,根据大小关系对其左右子结点分别调用递归函数。若当前结点就是要删除的结点,先判断若有一个子结点不存在,就将 root 指向另一个结点,如果左右子结点都不存在,那么 root 就赋值为空了,也正确。难点就在于处理左右子结点都存在的情况,需要在右子树找到最小值,即右子树中最左下方的结点,然后将该最小值赋值给 root,然后再在右子树中调用递归函数来删除这个值最小的结点,参见代码如下:

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {

        if(!root)
            return NULL;

        if(key < root->val){
            root->left = deleteNode(root->left, key);
            return root;
        }

        if(key > root->val){
            root->right = deleteNode(root->right, key);
            return root;
        }

        if(!root->right) return root->left;

        if(!root->left) return root->right;

        TreeNode* p = root, *minnode = root->right;
        while(minnode->left){
            p = minnode;
            minnode = minnode->left;
        }

        root->val = minnode->val;
        root->right = deleteMinNode(root->right);//在右子树中调用递归函数来删除这个值最小的结点
        return root;
    }

private:
    TreeNode* deleteMinNode(TreeNode* root){

        if(!root->left) return root->right;
        root->left = deleteMinNode(root->left);
        return root;
    }
};
问题15:Convert Sorted Array to Binary Search Tree(给定一个有序数组建立一棵二分搜索树)

原题


/// Recursion
/// Time Complexity: O(n)
/// Space Complexity: O(logn)
class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        if (nums.size() == 0){
            return NULL;
        }
        return buildTree(nums,0,nums.size()-1);
    }

private:
    TreeNode* buildTree(const vector<int>& nums, int l, int r){
        if (l > r){
            return NULL;
        }
        if (l == r){
            return new TreeNode(nums[l]);
        }

        int mid= (l+r)/2;
        TreeNode* treeNode = new TreeNode(nums[mid]);
        treeNode->left = buildTree(nums,l, mid-1);
        treeNode->right = buildTree(nums,mid+1,r);
        return treeNode;
    }
};
问题15:Kth Smallest Element in a BST

原题
Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.
Note:
You may assume k is always valid, 1 ≤ k ≤ BST’s total elements.

Example 1:

Input: root = [3,1,4,null,2], k = 1
   3
  / \
 1   4
  \
   2
Output: 1

Example 2:

Input: root = [5,3,6,2,4,null,null,1], k = 3
       5
      / \
     3   6
    / \
   2   4
  /
 1
Output: 3
/// Inorder Traversal
/// Time Complexity: O(n)
/// Space Complexity: O(h) where h is the height of the BST
class Solution {

private:
    int index;

public:
    int kthSmallest(TreeNode* root, int k) {
        index = 0;
        return kthSmallestNode(root, k)->val;
    }

private:
    TreeNode* kthSmallestNode(TreeNode* node, int k){

        if(node == NULL)
            return NULL;

        TreeNode* res = kthSmallestNode(node->left, k);
        if(res) return res;

        index ++;
        if(index == k)
            return node;

        return kthSmallestNode(node->right, k);
    }
};

今天的leetcode真题的学习就到这里了,总结一下这几天的学习,开始有点不耐烦这种学习状态了,开始有点厌倦了,接下来应该换一下学习方式了,就是要多看看书了,加油!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值