二叉树和递归-刷题笔记

在这里插入图片描述

1、二叉树最小深度

Leetcode 111
【题目】
给定一个二叉树,找出其最小深度。

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

说明: 叶子节点是指没有子节点的节点。

示例:

给定二叉树 [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回它的最小深度 2.

最小深度条件判断的和最大深度不一样,这个要注意

/**
 * 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 {
public:
    int minDepth(TreeNode* root) {
        if(root==NULL)
            return 0;
        else if(root->left!=NULL&&root->right!=NULL)
        {
            return min(minDepth(root->left),minDepth(root->right))+1;
        }
        else if(root->left==NULL)
        {
            return minDepth(root->right)+1;
        }
        else
        {
            return minDepth(root->left)+1;
        }
        
    }
};

2、翻转二叉树

Leetcode 226
【题目】
翻转一棵二叉树。

示例:

输入:
4
/
2 7
/ \ /
1 3 6 9
输出:
4
/
7 2
/ \ /
9 6 3 1

用递归的方法思考

/**
 * 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 {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root==NULL)
            return NULL;
        TreeNode* L= invertTree(root->left);
        TreeNode* R = invertTree(root->right);
        root->left=R;
        root->right=L;
        return root;

    }
};

3、相同的树

Leetcode 100
【题目】
给定两个二叉树,编写一个函数来检验它们是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例 1:

输入:
1 1
/ \ /
2 3 2 3
[1,2,3], [1,2,3]
输出: true

示例 2:

输入:
1 1
/
2 2
[1,2], [1,null,2]
输出: false

示例 3:

输入:
1 1
/ \ /
2 1 1 2
[1,2,1], [1,1,2]
输出: false

用递归的方法,递归的关键就是终止条件和递归过程

上代码

/**
 * 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 {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(p==NULL&&q==NULL)
        return true;
        else if(p==NULL||q==NULL)
        return false;
        if(p->val!=q->val)
        {
            return false;
        }
        else
        {
            return (isSameTree(p->left,q->left)&&isSameTree(p->right,q->right));            
        }
        
    }
};

4、对称二叉树

Leetcode 101
【题目】
给定一个二叉树,检查它是否是镜像对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

1
/
2 2
/ \ /
3 4 4 3

但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:

1
/
2 2
\
3 3

我是把之前的总结了一下,先镜像,之后再比较左右是否相等。

/**
 * 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 {
public:
    bool isSymmetric(TreeNode* root) {
        if(root==NULL)
        return true;
        TreeNode* t = reverse(root->right);
        return same(root->left,t);
        
    }
    TreeNode* reverse(TreeNode* root)
    {
        if(root==NULL)
        {
            return NULL;
        }
        TreeNode* L = reverse(root->left);
        TreeNode* R = reverse(root->right);
        root->left=R;
        root->right=L;
        return root;
    }
    bool same(TreeNode*p, TreeNode*q)
    {
        if(p==NULL&&q==NULL)
        return true;
        else if (p==NULL||q==NULL)
        return false;
        if(p->val!=q->val)
            return false;
        else
            return same(p->left,q->left)&&same(p->right,q->right);

    }
};

还有就是在原地用迭代的方式,最主要的是要看可以迭代的部分,这里需要的注意就要比较到第二层的结点之间。呀呀呀呀,说明白一点,就是找规律嘛,总结他们的关系是可重复的,可以用一个整体去表达。
上代码

/**
 * 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 {
public:
    bool isSymmetric(TreeNode* root) {
        if(root==NULL)
        return true;
        return isMirror(root,root);
        
        
    }
    
    bool isMirror(TreeNode* p , TreeNode* q)
    {
        if(p==NULL&&q==NULL)
            return true;
        if(p==NULL||q==NULL)
            return false;

        return((p->val==q->val)&&isMirror(p->left,q->right)&&isMirror(p->right,q->left));
    }
};

5、完全二叉树的节点数

Leetcode 222
【题目】
给出一个完全二叉树,求出该树的节点个数。

说明:

完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

示例:

输入:
1
/
2 3
/ \ /
4 5 6
输出: 6

我先用递归做的,应该二分查找和队列也可以,先贴上递归的方法

/**
 * 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 {
public:
    int countNodes(TreeNode* root) {
        if(root==NULL)
            return 0;
        if(root->left==NULL)
            return 1;
        else if(root->left!=NULL&&root->right==NULL)
            return 2;
        else
            return (countNodes(root->left)+countNodes(root->right))+1;

    }
};

6、平衡二叉树

Leetcode 110
【题目】
给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

示例 1:

给定二叉树 [3,9,20,null,null,15,7]

3
/
9 20
/
15 7
返回 true 。

示例 2:

给定二叉树 [1,2,2,3,3,null,null,4,4]

  1
  / \
 2   2
/ \

3 3
/
4 4
返回 false 。

用递归的方法,求出每层的层数

/**
 * 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 {
public:
    bool isBalanced(TreeNode* root) {
        if(root==NULL)
            return true;
        if(abs(height(root->left)-height(root->right))>1)
            return false;
        else
            return isBalanced(root->left)&&isBalanced(root->right);
        
    }

    int height(TreeNode* root)
    {
        if(root==NULL)
            return 0;
        else
            return max(height(root->left),height(root->right))+1;
    }
};

7、路径总和

Leetcode 112
【题目】
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

说明: 叶子节点是指没有子节点的节点。

**示例: **

给定如下二叉树,以及目标和 sum = 22,
5
/
4 8
/ /
11 13 4
/ \
7 2 1
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。

用递归的方法完成

/**
 * 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 {
public:
    bool hasPathSum(TreeNode* root, int sum) {
        if(root==NULL)
            return false;
        if(root->left==NULL&&root->right==NULL)
            return root->val==sum;
        return hasPathSum(root->left,sum-root->val)||hasPathSum(root->right,sum-root->val);
        
    }
};

8、左叶子之和

Leetcode 404
【题目】
404. 左叶子之和
计算给定二叉树的所有左叶子之和。

示例:

3
/
9 20
/
15 7
在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24

用递归的方法实现

/**
 * 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 {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        if(root==NULL||root->left==NULL&&root->right==NULL)
            return 0;
        
        if(root->left==NULL)
        {
            return sumOfLeftLeaves(root->right);
        }
        if(root->left->left==NULL&&root->left->right==NULL)
            return root->left->val+ sumOfLeftLeaves(root->right);
        else
            return sumOfLeftLeaves(root->left)+sumOfLeftLeaves(root->right);
        

    }
};

或者用队列迭代,求出所有的左变的叶子节点

9、路径总和(II)

【题目】
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。

说明: 叶子节点是指没有子节点的节点。

示例:

给定如下二叉树,以及目标和 sum = 22,
5
/
4 8
/ /
11 13 4
/ \ /
7 2 5 1
返回:
[
[5,4,11,2],
[5,8,4,5]

用深度优先的方法和递归的方法。

深度优先和广度优先要会。
深度优先用的是数组,其实也有点像栈,先入后出。
广度优先在在二叉树中常用在层序遍历中,先入先出。

上代码

/**
 * 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 {
public:
    vector<vector<int> > res;
    vector<int> temp;
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        
        if(root==NULL)
            return res;
        DFS(root,sum);
        return res;
        
    }
    void DFS(TreeNode* root,int sum)
    {
        int sum_temp = sum-root->val;
        temp.push_back(root->val);
        if(sum_temp==0&&root->left==NULL&&root->right==NULL)
        {
            res.push_back(temp);
        }
        if(root->left)
        {
            DFS(root->left,sum_temp);
        }
        if(root->right)
        {
            DFS(root->right,sum_temp);
        }
        temp.pop_back();
    }
};

10、路径总和III

leetcode 437
【题目】
给定一个二叉树,它的每个结点都存放着一个整数值。

找出路径和等于给定数值的路径总数。

路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。

示例:

root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
10
/
5 -3
/ \
3 2 11
/ \
3 -2 1
返回 3。和等于 8 的路径有:

  1. 5 -> 3
  2. 5 -> 2 -> 1
  3. -3 -> 11

要理解分治的思想
重点是递归的终止条件和递归的过程。
这个题目用递归的思想,首先是每个节点都考虑和为sum的情况,然后相加

/**
 * 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 {
public:
    int pathSum(TreeNode* root, int sum)
    {
        if(root==NULL)
            return 0;
        int sum_node=0;
        sum_node=nodeSum(root,sum);
        if(root->left)
        {
            sum_node+=pathSum(root->left,sum);

        }
        if(root->right)
        {
            sum_node+=pathSum(root->right,sum);
        }
        return sum_node;
    }
    
    int nodeSum(TreeNode* root, int sum) {
        
        if(root==NULL)
            return 0;
        int num;
        if(root->val==sum)
            num=1;
        else 
            num=0;       
        int temp_num;
        temp_num=sum-root->val;
        return num+nodeSum(root->left,temp_num)+nodeSum(root->right,temp_num);


    }
};

11、二叉搜索树的公共祖先

Leetcode 235
【题目】
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
在这里插入图片描述

示例 1:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6。

示例 2:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。
说明:
所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉搜索树中。

最主要的是要理解二叉搜索树的含义。公共祖先,说明是第一个在他们两个之间的数。这个要理解,然后要想到用递归的方法如何实现

/**
 * 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 {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==NULL)
            return NULL;
        if(root->val<p->val&&root->val<q->val)
        return lowestCommonAncestor(root->right,p,q);
        if(root->val>p->val&&root->val>q->val)
        return lowestCommonAncestor(root->left,p,q);

        return root;
        
    }
};

12、二叉树的系列化和反序列化

Leetcode 297
序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。

请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

示例:

你可以将以下二叉树:

1

/
2 3
/
4 5

序列化为 “[1,2,3,null,null,4,5]”
提示: 这与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。

说明: 不要使用类的成员 / 全局 / 静态变量来存储状态,你的序列化和反序列化算法应该是无状态的。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

用队列来保存二叉树

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

    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        //BFS 
        // Time Complexity: O(n)
        // Space Complexity: O(n)
        if(!root) //输入为空
            return "[null]";

            string ret="[";
            queue<TreeNode*>q;
            q.push(root);
            ret += to_string(root->val);//输入根结点
            while(!q.empty())
            {
                TreeNode* cur=q.front();
                q.pop();

                if(cur->left)
                {
                    ret += ","+to_string(cur->left->val);
                    q.push(cur->left);
                }
                else
                    ret += ",null";
                if(cur->right)
                {
                    ret+=","+to_string(cur->right->val);
                    q.push(cur->right);
                }
                else   ret += ",null";
            }
            return ret+"]";

        
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        vector <string> vec = get_vector(data);

        if(vec.size()==0||(vec.size()==1&&vec[0]=="null"))
            return NULL;
        
        TreeNode* root = new TreeNode(atoi(vec[0].c_str()));
        queue<TreeNode*>q;
        q.push(root);
        int index = 1 ;
        while(!q.empty())
        {
            TreeNode* cur = q.front();
            q.pop();

            assert(vec.size()-index>=2); //确保有两个及以上的结点
            if(vec[index]!="null") //不是空节点
            {
                cur->left = new TreeNode(atoi(vec[index].c_str()));
                q.push(cur->left);
            }
            index ++;

            if(vec[index]!="null")
            {
                cur->right = new TreeNode(atoi(vec[index].c_str()));
                q.push(cur->right);
            }
            index ++;
        }
        return root;
        
    }

    private:
    vector<string> get_vector(const string& data) //将字符串分隔转换成数组
    {
        string s = data.substr(1,data.size()-2)+","; //去除前后两个[]

        vector<string> res;

        int i = 0 ;
        while(i < s.size())
        {
            int comma = s.find(',',i); // i 位置之后第一次出现","的位置
            res.push_back(s.substr(i,comma-i));
            i = comma +1;

        }
        return res;
    }
};

// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));

13、将有序数组转化为二叉搜索树

在这里插入图片描述

二叉搜索树的中序遍历是升序序列,题目给定的数组是按照升序排序的有序数组,因此可以确保数组是二叉搜索树的中序遍历序列。

选择中间位置左边的数字作为根节点,则根节点的下标为 m i d = ( l e f t + r i g h t ) / 2 mid=(left+right)/2 mid=(left+right)/2,此处的除法为整数除法
在这里插入图片描述

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/solution/jiang-you-xu-shu-zu-zhuan-huan-wei-er-cha-sou-s-33/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

/**
 * 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 {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return help(nums,0,nums.size()-1);

    }
    TreeNode* help(vector<int>& nums, int left ,int right)
    {
        if(left>right)
            return NULL;
        int mid = left+(right-left)/2;
        TreeNode* root = new TreeNode(nums[mid]);
        root->left = help(nums,left,mid-1);
        root->right = help(nums,mid+1, right);
        return root;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值