代码随想录算法训练营第十七天|LeetCode110.平衡二叉树、LeetCode257.二叉树的所有路径、LeetCode404.左叶子之和
2023年3月16日 第三十天补
文章目录
110. 平衡二叉树
题目链接:110. 平衡二叉树
思路:
- 一个平衡二叉树,左右两侧子树的高度差不大于一
- 这个遍历我们需要用后序遍历,因为只有知道左右子树的高速,才能判断当前节点的树是否是平衡二叉树
- 另外,如果有子树不是平衡二叉树,则整个树都不是平衡二叉树
时间复杂度:O(n),空间复杂度O(n)
代码:
class Solution {
public:
bool isBalanced(TreeNode* root) {
// 只有-1表示该树不是平衡二叉树
if(getHeight(root) != -1)
return ture;
else return false;
}
// 获取子树高度的函数
int getHeight(TreeNode*node)
{
if(node == nullptr)return 0;
// 获取左右子树的高度
auto left = getHeight(node->left);
auto right = getHeight(node->right);
// 用-1代表不是平衡二叉树
// 如果子树或当前树不是平衡二叉树,则返回-1
if(left == -1 || right == -1 || std::abs(right - left) > 1)return -1;
// 否则返回当前节点的高度
else return std::max(right,left)+1;
}
};
总结:
- 因为函数的返回值既要有高度又要有是否是平衡二叉树的判断,我原来在这里定义了一个结构体
- 听了carl哥的讲解之后理解到,如果不是平衡二叉树,高度就没有意义了,那么就找一个高度不存在的值作为判断值,比如-1返回就行
- 做题体验:
嘿嘿(哈哈>嘿嘿>哎哎>嘤嘤) - 时间:
未计 一刷
257. 二叉树的所有路径
题目链接:257. 二叉树的所有路径
思路:
- 这道题其实也是一个遍历找叶子节点的过程,遍历的时候要记录下所有经过的节点
- 找到叶子节点就将路径放入结果集中
- 这道题我写三个题解
- 解法1:用代码比较精简的写法
- 解法2:在代码逻辑中考虑到回溯
- 解法3:看carl哥视频优化解法2
时间复杂度:O(n),空间复杂度O(n)
解法1
代码:
class Solution
{
public:
vector<string> binaryTreePaths(TreeNode *root)
{
std::string path;
if (root != nullptr)travelNode(root, path);
return result;
}
void travelNode(TreeNode *node, std::string path)
{
// 在路径上加上当前元素
path = path + std::to_string(node->val) + "->";
// 如果是叶子节点,就放入路径的结果集,记得要删掉最后的"->"
if (node->left == nullptr && node->right == nullptr)result.push_back(path.substr(0, path.size() - 2));
// 如果还有孩子就递归
if (node->left != nullptr)travelNode(node->left, path);
if (node->right != nullptr)travelNode(node->right, path);
}
std::vector<string> result;
};
解法2
- 上一版代码每递归一次,都会拷贝一个新的string对象出来,会比较浪费空间
- 这一版在函数的传参是用引用
- 所以要注意的是,递归在回溯的过程要删除前一个节点的记录
代码:
class Solution
{
public:
vector<string> binaryTreePaths(TreeNode *root)
{
std::string path;
if (root != nullptr)
{
travelNode(root, path);
}
return result;
}
// 是用回溯的原因,是因为参数用到了引用
void travelNode(TreeNode *node, std::string &path)
{
path = path + std::to_string(node->val) + "->";
if (node->left == nullptr && node->right == nullptr)
{
result.push_back(path.substr(0, path.size() - 2));
return;
}
if (node->left != nullptr)
{
travelNode(node->left, path);
// 注意要删的是刚遍历过的节点,不是当前节点
// std::to_string(node->left->val).size() 代表刚遍历过的节点写入路径的长度
// 2 代表->的长度
auto valLength = std::to_string(node->left->val).size();
path = path.substr(0, path.size() - valLength - 2);
}
if (node->right != nullptr)
{
travelNode(node->right, path);
auto valLength = std::to_string(node->right->val).size();
path = path.substr(0, path.size() - valLength - 2);
}
}
std::vector<string> result;
};
解法3
- 上一版代码有此问题:
- 每次添加路径的时候都要从int型转换成string,逻辑上不容易理解
- 每次回溯删值得时候要注意长度,注意删的是哪个节点的值
- 这版代码就用一个std::vector 对象作为形参
- 每次添加路径只要尾插当前元素的值即可
- 删除路径只要抛出尾部元素
- 然后需要再写一个生成string对象的函数,让代码整体显得更加整洁一些
代码:
class Solution
{
public:
vector<string> binaryTreePaths(TreeNode *root)
{
std::vector<int> path;
std::vector<string> result;
if (root != nullptr)
{
travelNode(root, path,result);
}
return result;
}
void travelNode(TreeNode *node, std::vector<int> &path,std::vector<string> & result)
{
path.push_back(node->val);
if (node->left == nullptr && node->right == nullptr)
{
result.push_back(genString(path));
return;
}
if (node->left != nullptr)
{
travelNode(node->left, path,result);
path.pop_back();
}
if (node->right != nullptr)
{
travelNode(node->right, path,result);
path.pop_back();
}
}
std::string genString(std::vector<int> path)
{
std::string res;
if(!path.empty())
{
res += std::to_string(path[0]);
}
for(int i =1;i<path.size();++i)
{
res +="->";
res +=std::to_string(path[i]);
}
return res;
}
};
总结:
- 理解起来不是太难,加油吧
- 做题体验:
哈哈(哈哈>嘿嘿>哎哎>嘤嘤) - 时间:
未计 一刷
404. 左叶子之和
题目链接:404. 左叶子之和
思路:
- 我认为这道题的关键,是找到左叶子的父亲
时间复杂度:O(n),空间复杂度O(n)
代码:
class Solution
{
public:
int sumOfLeftLeaves(TreeNode *root)
{
getLeftNode(root);
return sum;
}
void getLeftNode(TreeNode *node)
{
// 判断是否是左叶子的父亲
if (node->left != nullptr && node->left->left == nullptr && node->left->right == nullptr)
sum += node->left->val;
if (node->left != nullptr)
getLeftNode(node->left);
if (node->right != nullptr)
getLeftNode(node->right);
}
int sum;
};
总结:
- 理解起来不是太难,加油吧
- 做题体验:
哈哈(哈哈>嘿嘿>哎哎>嘤嘤) - 时间:
未计 一刷
本文介绍了如何解决LeetCode中的三道二叉树问题:110.平衡二叉树、257.二叉树的所有路径和404.左叶子之和。分别使用后序遍历、回溯等方法,探讨了不同解题策略,并分析了时间复杂度和空间复杂度。


被折叠的 条评论
为什么被折叠?



