上篇文章记录了我做递归题目的一点点灵感,然后我现在发现我高兴的太早了。。。
这不趁着五一假期结束之前赶紧又做了一题递归题目,然后经过我仔细分析,根据我前面总结的经验,感觉还好,用给的示例运行也是对的,然后我很高兴的点击了提交,果不其然,解答错误。。。。。
话不多说,来看看怎么错的吧!
题目
110. 平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
提交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 {
// 定义计算树深度的函数
int tree_depth(TreeNode* node){
// 递归结束条件(特殊情况)
if(node == nullptr) return 0;
if(node->left == nullptr && node->right == nullptr) return 1;
// 递归调用
int l = tree_depth(node->left) + 1;
int r = tree_depth(node->right) + 1;
// 最终返回结果
return max(l, r);
}
public:
bool isBalanced(TreeNode* root) {
/*
可以将递归题目的解答分为3块:
(1)第一块:递归结束条件(特殊情况),含有return语句
(2)第二块:递归调用,调用函数本身,整体解决问题
(3)第三块:返回最终结果,含有return语句
*/
// 递归结束条件(特殊情况)
if(root == nullptr) return true;
// 计算左右子树的深度
int left_depth = tree_depth(root->left);
int right_depth = tree_depth(root->right);
// 判断是否为平衡树
if(fabs(left_depth-right_depth)>1)
return false;
else
return true;
// 递归调用
bool left_tree = isBalanced(root->left);
bool right_tree = isBalanced(root->right);
// 最终返回结果
return left_tree && right_tree;
}
};
错误示例: [1,2,2,3,null,null,3,4,null,null,4]
刚开我有点懵,但是经过我仔细分析之后,我发现根本就没有实现递归,在计算第一次左子树和右子树的时候就return 了答案!但我们这个题目要求的是每一个节点都必须满足平衡二叉树的特点,所以就错了。。。
提交2(√):自顶向下
然后我就对代码稍微改动了一下,我先不return,我先把结果用一个变量记录下来,等递归完了一块返回,其实我改的时候还是有点懵的,不过感觉就是这个理,然后就对了。
/**
* 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 tree_depth(TreeNode* node){
// 递归结束条件(特殊情况)
if(node == nullptr) return 0;
if(node->left == nullptr && node->right == nullptr) return 1;
// 递归调用
int l = tree_depth(node->left) + 1;
int r = tree_depth(node->right) + 1;
// 最终返回结果
return max(l, r);
}
public:
bool isBalanced(TreeNode* root) {
/*
可以将递归题目的解答分为3块:
(1)第一块:递归结束条件(特殊情况),含有return语句
(2)第二块:递归调用,调用函数本身,整体解决问题
(3)第三块:返回最终结果,含有return语句
*/
bool is = true;
// 递归结束条件(特殊情况)
if(root == nullptr) return true;
// 计算左右子树的深度
int left_depth = tree_depth(root->left);
int right_depth = tree_depth(root->right);
// 判断是否为平衡树
if(fabs(left_depth-right_depth)>1)
is = false;
else
is = true;
// 递归调用
bool left_tree = isBalanced(root->left);
bool right_tree = isBalanced(root->right);
// 最终返回结果
return left_tree && right_tree && is;
}
};
然后我去看了一下官方的题解,发现官方题解真的很间接,而我这。。。又臭又长,哎没办法,毕竟还是个小菜鸡,慢慢来吧,能运行成功就不错了(自我鼓励一下!)
然后通过看解析,发现有两种递归的方法:自顶向下和自底向上两种。我用的这种属于自顶向下,就是我相当于用了两遍递归,因为我需要计算每一个节点的深度,而计算节点的函数又是递归的,所以这样时间复杂度会很高!
请原谅我似乎刚了解了自顶向下和自底向上这两种递归方法。然后我又看了自底向上的递归方法。
提交3(√):自底向上
/**
* 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 depth(TreeNode* node){
if(node == nullptr)
return 0;
// 当到达树的最低端才会开始执行相应操作
int l = depth(node->left);
int r = depth(node->right);
if(l == -1 || r == -1 || fabs(l-r) > 1)
return -1;
return max(l, r)+1;
}
public:
bool isBalanced(TreeNode* root) {
return depth(root) >= 0;
}
};
自底向上可以看到,在计算树的深度的时候,他刚开始是不进行操作的,先递归到树的最底部,然后在进行相应操作,如果出现非平衡现象就返回-1,否则就返回树的高度。这样就需要递归一次即可!时间复杂度会降低很多。
怎么朔呢,修行还不够,还得继续努力,熟能生巧吧,多做多练,没别人聪明,就得比别人努力一点呗!
Keep learning! Keep moving!