1 题目描述
题目链接:叶子相似的树
2 解答思路
递归分为三步,接下来就按照这三步来思考问题
第一步:挖掘出相同的子问题 (关系到具体函数头的设计)
第二步:只关心具体子问题做了什么 (关系到具体函数体怎么写,是一个宏观的过程)
第三步:找到递归的出口,防止死递归 (关系到如何跳出递归)
2.1 相同的子问题(函数头设计)
从题目的描述中可以看到,最终的目的是找到二叉树的叶子节点。
这里相同的子问题就是:找A的叶子节点,就是找A的左子树的叶子节点和找A的右子树的叶子节点
下面是leetcode给的函数头:
bool leafSimilar(TreeNode* root1, TreeNode* root2) {
}
从上面可以看出,传入的是两个二叉树,最后返回true
或者 false
.
根据我们得到的相同的子问题,里面有两个关键点:
1.二叉树
2.叶子节点
因此,我们的函数头需要两个参数:一个是TreeNode*
类型的(存储二叉树),一个是vector<int>
类型的(存储叶子节点)。
基于此,我们自己设计一个函数头:
void leaf(TreeNode* root, vector<int>& res)
{
}
注意:因为我们最后是拿vector<int>
里面存储的叶子节点来比较,所以函数没有返回值。
2.2 具体的子问题做了什么(函数体的实现)
传入的参数是一个TreeNode* root
, 一个vector<int> res
,具体的子问题:
判断该子树是不是叶子节点,是就加入到res中,不是就继续找它的左子树的叶子节点和找右子树的叶子节点
因此,下面就是函数体的实现:(顺便讲解了递归的出口)
void leaf(TreeNode* root, vector<int>& res)
{
//递归的出口
if (root == nullptr)
return;
//如果是叶子节点就加入到res中
if (root->left == nullptr && root->right == nullptr)
res.push_back(root->val);
//不是叶子节点就左子树和右子树中继续执行此操作
leaf(root->left, res);
leaf(root->right, res);
}
3 总结
class Solution {
public:
bool leafSimilar(TreeNode* root1, TreeNode* root2) {
vector<int> res1, res2;
leaf(root1, res1);
leaf(root2, res2);
if (res1.size() != res2.size())
return false;
for (int i = 0; i < res1.size(); ++ i)
{
if (res1[i] != res2[i])
return false;
}
return true;
}
void leaf(TreeNode* root, vector<int>& res)
{
//递归的出口
if (root == nullptr)
return;
//如果是叶子节点就加入到res中
if (root->left == nullptr && root->right == nullptr)
res.push_back(root->val);
//不是叶子节点就左子树和右子树中继续执行此操作
leaf(root->left, res);
leaf(root->right, res);
}
};
相同的子问题: 找二叉树的叶子节点就是找二叉树的左子树的叶子节点和右子树的叶子节点
只关心具体子问题做了什么:判断该节点是不是叶子节点,是就插入到vector中,不是就继续去左子树和右子树寻找叶子节点
递归的出口:节点为空