一、题目打卡
1.1 平衡二叉树
题目链接:. - 力扣(LeetCode)
题目可以分为先序遍历和后序遍历两个方式进行,前者是遍历所有的节点,并计算每个节点的高度,后者是递归,然后计算每个节点的深度,并且可以在计算到不满足的以后直接剪枝:
class Solution {
private:
int calculate_Depth(TreeNode* root){
if(!root) return 0;
return max(calculate_Depth(root->left),calculate_Depth(root->right)) + 1;
}
public:
bool isBalanced(TreeNode* root) {
if(!root) return true;
int m = calculate_Depth(root->left);
int n = calculate_Depth(root->right);
bool flag = abs(m - n) < 2;
return flag && isBalanced(root->left) && isBalanced(root->right);
}
};
class Solution {
private:
int recur(TreeNode* root){
if(!root) return 0;
int m = recur(root->left);
if(m == -1) return -1;
int n = recur(root->right);
if(n == -1) return -1;
int ret = abs(m - n) < 2 ? max(m,n)+1 : -1; // 中,最后处理返回值,后续遍历
return ret;
}
public:
bool isBalanced(TreeNode* root) {
return recur(root) == -1 ? false : true;
}
};
1.2 二叉树的所有路径
这个题目考查的其实是回溯的思想,一开始我虽然也是回溯的思想然后尝试写了一下,如下:
class Solution {
private:
string tmp;
vector<string> res;
void recur(TreeNode* root){
if(!root) return;
if(root->left == nullptr && root->right == nullptr){
tmp = tmp + "->" + to_string(root->val);
res.push_back(tmp);
// tmp.pop_back();
// tmp.pop_back();
// tmp.pop_back();
while(tmp.back() != '>') tmp.pop_back();
tmp.pop_back();
tmp.pop_back();
return;
}
if(tmp.empty()) tmp += to_string(root->val);
else tmp = tmp + "->" + to_string(root->val);
recur(root->left);
recur(root->right);
if(tmp.size() == 1) tmp.pop_back();
else{
while(tmp.back() != '>') tmp.pop_back();
tmp.pop_back();
tmp.pop_back();
}
}
public:
vector<string> binaryTreePaths(TreeNode* root) {
if(!root || (!root->left && !root->right)) return {to_string(root->val)};
recur(root);
return res;
}
};
但是这样忽略了一个很关键的事情,就是数组有正有负,并且有可能有很多位,所以这样会很容易出错,然后借助 chat 分析了一下,我自己又重新理了一个思路:
class Solution {
private:
void recur(TreeNode* root,vector<string> &res, string tmp){
if(!root) return;
if(!root->left && !root->right){
if(!tmp.empty())tmp = tmp + "->" + to_string(root->val);
else tmp += to_string(root->val);
res.push_back(tmp);
return;
}
if(!tmp.empty())tmp = tmp + "->" + to_string(root->val);
else tmp += to_string(root->val);
recur(root->left,res,tmp);
recur(root->right,res,tmp);
}
public:
vector<string> binaryTreePaths(TreeNode* root) {
if(!root) return {};
vector<string> res;
string tmp;
recur(root,res,tmp);
return res;
}
};
这样其实利用了递归过程中会存储每一层的信息,这里比较关键的是 string tmp 并没有建立对 tmp 的引用,这样就达到了存储的目的,但是这样很明显很耗费内存,然后看了答案,答案是使用了一个 vector 存储所有节点的数字,然后最后在统一变成字符串,这样其实更合理一点:
class Solution {
private:
void recur(TreeNode* root,vector<string> &res, vector<int>& tmp){
tmp.push_back(root->val);
if(!root->left && !root->right){
string _tmp = "";
for(int i = 0; i < tmp.size();i++){
_tmp += to_string(tmp[i]);
_tmp += "->";
}
_tmp.pop_back();
_tmp.pop_back();
res.push_back(_tmp);
return;
}
if(root->left){
recur(root->left,res,tmp);
tmp.pop_back();
}
if(root->right){
recur(root->right,res,tmp);
tmp.pop_back();
}
}
public:
vector<string> binaryTreePaths(TreeNode* root) {
if(!root) return {};
vector<string> res;
vector<int> tmp;
recur(root,res,tmp);
return res;
}
};
1.3 左叶子之和
题目链接:. - 力扣(LeetCode)
class Solution {
private:
int res = 0;
void recur(TreeNode* root){
if(!root) return;
if(root->left && !root->left->left && !root->left->right) res += root->left->val;
recur(root->left);
recur(root->right);
}
public:
int sumOfLeftLeaves(TreeNode* root) {
recur(root);
return res;
}
};
看了答案,答案采用的是后序遍历的方式,我感觉比较抽象一点,我还是习惯用这种整体的方式,然后采用前序遍历的方式,感觉比较直观,这里需要注意的是对题目的理解,注意是所有的左叶子节点的和,因而在累加的判断条件中,需要判断的不仅仅是第一个条件:root->left,还需要加上后面两个,因为加上了这个节点才是叶子节点。
答案:
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
if (root == NULL) return 0;
if (root->left == NULL && root->right== NULL) return 0;
int leftValue = sumOfLeftLeaves(root->left); // 左
if (root->left && !root->left->left && !root->left->right) { // 左子树就是一个左叶子的情况
leftValue = root->left->val;
}
int rightValue = sumOfLeftLeaves(root->right); // 右
int sum = leftValue + rightValue; // 中
return sum;
}
};