第一题:
思路是求左子树和右子树的高度差,用后序遍历,递归三部曲中前两个都能弄清楚,但是最后的单层递归逻辑没弄明白,所以没能AC,以下是看了视频后自己写的:
class Solution {
public:
int getHight(TreeNode* node) {
if (node == nullptr) return 0;
int left = getHight(node->left);
if (left == -1) return -1; //如果左子树已经不平衡,返回-1
int right = getHight(node->right);
if (right == -1) return -1; //如果右子树已经不平衡,返回-1
if (abs(left - right) > 1) return -1; //判断左右子树是否平衡
else return 1 + max(left, right); //平衡的话返回高度
}
bool isBalanced(TreeNode* root) {
int result = getHight(root);
if (result < 0) return false;
else return true;
}
};
第二题:
大概思路是正确的,使用前序遍历,在走到叶子节点的时候往上返回一个(回溯)。就是string转换的细节以及输出上要注意,节点值与节点值之间要用“->"连接起来:
class Solution {
public:
void getvalue(TreeNode* node, string path, vector<string>& paths) {
if (node == nullptr) return;
path += to_string(node->val);
if (node->left == nullptr && node->right == nullptr) {
paths.push_back(path);
}
else {
path += "->";
getvalue(node->left, path, paths);
getvalue(node->right, path, paths);
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> paths;
getvalue(root, "", paths);
return paths;
}
};
按照回溯思路写的,注意path是vector<int>类型,才可以用&,如果是string&,那么每次pop只能pop掉一个char类型的数字,是不正确的(节点的val可能是十位、百位):
class Solution {
public:
void getpath(TreeNode* node, vector<int>& path, vector<string>& paths) {
path.push_back(node->val);
if (node->left == nullptr && node->right == nullptr) {
string res;
for (auto it = path.begin(); it != path.end()-1; it++) {
res += to_string(*it) + "->";
}
res += to_string(path.back());
paths.push_back(res);
return;
}
if (node->left) {
getpath(node->left, path, paths);
path.pop_back(); //因为path是引用,一直在修改,因此这里要pop掉最后加入的内容,这就是回溯
}
if (node->right) {
getpath(node->right, path, paths);
path.pop_back();
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<int> path;
vector<string> paths;
if (root == NULL) return paths;
getpath(root, path, paths);
return paths;
}
};
如果简化,就是在传参的时候不用引用,这样每次传进去的就是从根节点到父节点的路径,每次子节点的操作不会修改path,如此也就不用再弹出path.back(),此外因为一开始没有写if (node == null) return; 所以需要加上左右子树是否存在的判断:
class Solution {
public:
void getpath(TreeNode* node, vector<int> path, vector<string>& paths) {
path.push_back(node->val);
if (node->left == nullptr && node->right == nullptr) {
string res;
for (auto it = path.begin(); it != path.end()-1; it++) {
res += to_string(*it) + "->";
}
res += to_string(path.back());
paths.push_back(res);
return;
}
if (node->left) {
getpath(node->left, path, paths);
}
if (node->right) {
getpath(node->right, path, paths);
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<int> path;
vector<string> paths;
if (root == NULL) return paths;
getpath(root, path, paths);
return paths;
}
};
代码随想录的简化版,回溯隐藏在traversal(cur->left, path + "->", result);
中的 path + "->"
。 每次函数调用完,path依然是没有加上"->" 的,这就是回溯:
class Solution {
private:
void traversal(TreeNode* cur, string path, vector<string>& result) {
path += to_string(cur->val); // 中
if (cur->left == NULL && cur->right == NULL) {
result.push_back(path);
return;
}
if (cur->left) traversal(cur->left, path + "->", result); // 左
if (cur->right) traversal(cur->right, path + "->", result); // 右
}
public:
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> result;
string path;
if (root == NULL) return result;
traversal(root, path, result);
return result;
}
};
TIPS:回溯要和递归永远在一起!同在一个花括号里,一个递归对应一个回溯!
第三题:
已AC,递归法,终止条件为当节点不为左叶子节点时,返回。区分是不是左叶子节点,在递归调用的时候增加一个flag就行,flag会向下传递来源信息,1为向左,-1为向右,只有满足向左走且为叶子节点,才会累加进结果并返回:
class Solution {
public:
void getValue(TreeNode* node, int& res, int flag) {
if (node->left == nullptr && node->right == nullptr && flag == 1) {
res += node->val;
return;
}
if (node->left) getValue(node->left, res, 1);
if (node->right) getValue(node->right, res, -1);
return;
}
int sumOfLeftLeaves(TreeNode* root) {
if (root == nullptr) return 0;
int res = 0;
getValue(root, res, 0);
return res;
}
};
代码随想录的解法之前也想到过,但是觉得有点麻烦就没写,他是判断的父节点的左孩子是否是叶子节点,如果是就返回左孩子的val,然后左子树求得的值和右子树求得的值累加:
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;
}
};