110.平衡二叉树
平衡二叉树,也就是AVL树,实际上就是左右子树高度相差小于等于1的树。
1.超慢递归
树平衡 = 左子树平衡 + 右子树平衡 + 左右子树高度差小于1
int depth (TreeNode* root)
{
if (root == nullptr) return 0;
return max(depth(root->left), depth(root->right)) + 1;
}
bool isBalanced(TreeNode* root) {
if (root == nullptr) return true;
return isBalanced(root->left) && isBalanced(root->right) && abs(depth(root->left) - depth(root->right)) <= 1;
}
2.代码随想录的递归
这个比我自己想的好,一旦发现不平衡,可以一直上报回最顶层
// 返回以该节点为根节点的二叉树的高度,如果不是平衡二叉树了则返回-1
int getHeight(TreeNode* node) {
if (node == NULL) {
return 0;
}
int leftHeight = getHeight(node->left);
if (leftHeight == -1) return -1;
int rightHeight = getHeight(node->right);
if (rightHeight == -1) return -1;
return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);
}
bool isBalanced(TreeNode* root) {
return getHeight(root) == -1 ? false : true;
}
这个迭代法,说实话没什么效率,所以不写了。
257. 二叉树的所有路径
1.自己的方法
这个题目我选择了回溯,由于直接存字符串处理很难,而且不清楚val作为字符串的长度,所以先用vector存储序列,最后把它转化成字符串
这里我选择了全局变量,实际上传引用更好,一般来说工程中最好不要有全局变量
vector<int> seq;
vector<string> res;
string make_string(vector<int> seq)
{
string str;
for (auto& x: seq) str += to_string(x) + "->";
str.pop_back(); //删去结尾多出来的箭头
str.pop_back();
return str;
}
void dfs(TreeNode* root)
{
//当抵达叶子结点,则可以返回结果
if (root->left == nullptr && root->right == nullptr)
{
seq.push_back(root->val);
res.push_back(make_string(seq));
seq.pop_back();
}
if (root->left)
{
seq.push_back(root->val);
dfs(root->left);
seq.pop_back();
}
if (root->right)
{
seq.push_back(root->val);
dfs(root->right);
seq.pop_back();
}
}
vector<string> binaryTreePaths(TreeNode* root) {
stack<TreeNode*> s;
dfs(root);
return res;
}
2.代码随想录的方法
代码随想录的方法相比我自己的想法有这些提升:
1.引用优于全局变量,因为全局变量容易出现很难调试的错误(但是说实话,其实函数参数太多也不太好,这里没办法啦~)
2.有一个更好的命名,遍历是traversal,路径是path
3.把添加结点到path的任务提取出来,节省了类似的步骤。
但是我觉得还是单独写一个函数处理string的问题更好
string make_string(vector<int> seq)
{
string str;
for (auto& x: seq) str += to_string(x) + "->";
str.pop_back();
str.pop_back();
return str;
}
void traversal(TreeNode* root, vector<int>& path, vector<string>& res)
{
path.push_back(root->val);
//当抵达叶子结点,则可以返回结果
if (root->left == nullptr && root->right == nullptr)
{
res.push_back(make_string(path));
return;
}
if (root->left)
{
traversal(root->left, path, res);
path.pop_back();
}
if (root->right)
{
traversal(root->right, path, res);
path.pop_back();
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<int> path;
vector<string> res;
traversal(root, path, res);
return res;
}
继续优化,我们能不能省掉讨厌的处理字符串这一步(但是这里其实还有一个问题,就是按接下来的做法,面临大量重复的string,但是我们做算法题暂时不考虑这种性能问题)
这里利用了形参的复制省去了回溯的pop,但是这其实性能真的不好,而且让这个回溯看上去很别扭
void traversal(TreeNode* root, string path, vector<string>& res)
{
path += to_string(root->val);
//当抵达叶子结点,则可以返回结果
if (root->left == nullptr && root->right == nullptr)
{
res.push_back(path);
return;
}
if (root->left) traversal(root->left, path + "->", res);
if (root->right) traversal(root->right, path + "->", res);
}
vector<string> binaryTreePaths(TreeNode* root) {
string path;
vector<string> res;
traversal(root, path, res);
return res;
}
404.左叶子之和
1.递归
void traversal(TreeNode* root, int& res)
{
if (root->left != nullptr && root->left->left == nullptr && root->left->right == nullptr)
{
res += root->left->val;
}
if (root->left)
{
traversal(root->left, res);
}
if (root->right)
{
traversal(root->right, res);
}
}
int sumOfLeftLeaves(TreeNode* root) {
int res = 0;
traversal(root, res);
return res;
}
2.迭代
int sumOfLeftLeaves(TreeNode* root) {
int res = 0;
stack<TreeNode*> st;
if (root) st.push(root);
while (!st.empty())
{
TreeNode* cur = st.top();
st.pop();
if (cur != nullptr)
{
if (cur->right) st.push(cur->right);
if (cur->left)
{
st.push(cur->left);
if (cur->left->left == nullptr && cur->left->right == nullptr)
res += cur->left->val;
}
st.push(cur);
st.push(nullptr);
}
else
{
cur = st.top();
st.pop();
}
}
return res;
}