LeetCode 110. 平衡二叉树
思路:
平衡二叉树的特征:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。所以判断一棵树是否为二叉树,我们需要计算每个节点左右两颗子树的高度,并计算两颗子树高度差,如果绝对值超过1,则返回false。二叉树的高度和深度是有区别的。
- 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数。
- 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数。
在计算节点深度的时候,通常用前序遍历,从根节点往下寻找,而计算高度则正好相反,用的是后序遍历,从叶子节点往上寻找。当计算一颗树的最大深度的时候,既可以用前序遍历又可以用后序遍历,因为根节点的最大深度和高度是一样的。
在本题中,我们用后序遍历,用递归的方法分别求出当前节点下左子树和右子树的高度,如果左子树和右子树的高度差大于一,则返回false,如果小于等于1,则返回当前左右子树高度的最大值再加1,这个操作和104. 二叉树的最大深度里的代码完全一样,最后如果一直到根节点都没有子树不是完全二叉树,则返回true,否则返回false。
代码:
class Solution {
public:
bool isBalanced(TreeNode* root) {
if (root == nullptr)
return true;
if (countHeight(root) == -1)
return false;
else
return true;
}
int countHeight(TreeNode* root)
{
if (root == nullptr)
return 0;
int leftHeight = countHeight(root->left);
if (leftHeight == -1)
return -1;
int rightHeight = countHeight(root->right);
if (rightHeight == -1)
return -1;
if (abs(leftHeight - rightHeight) > 1)
return -1;
return 1 + max(leftHeight, rightHeight);
}
};
LeetCode 257. 二叉树的所有路径
思路:
寻找所有路径通常都是用回溯法。首先声明一个数组用来记录走过的路径
vector<int>paths;
每次找到路径后,都需要把该路径append到最终结果上。回溯的核心思想在于,当前路径走完后,将paths的最后一个元素pop出来,也就是说回到上一个状态,然后尝试新的路径。在二叉树中,每个节点都有两条路径可以选择,如下代码
if (root->left)
{
paths.push_back(root->left->val);
dfs(root->left, ans, paths);
// 回溯
paths.pop_back();
}
if (root->right)
{
paths.push_back(root->right->val);
dfs(root->right, ans, paths);
// 回溯
paths.pop_back();
}
如果左节点不为空,就往左节点走,把当前路径添加到paths上,然后调用dfs递归寻找下一条路径,从dfs返回后,pop出当前走的这条路,然后尝试走右节点,这就是一个很经典的递归+回溯的算法。找到叶子节点后,用一个循环将当前路径转换成string在push到最终结果。
完整代码:
class Solution {
public:
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> ans;
vector<int> paths;
paths.push_back(root->val);
dfs(root, ans, paths);
return ans;
}
void dfs(TreeNode* root, vector<string> &ans, vector<int> &paths)
{
if (root->left)
{
paths.push_back(root->left->val);
dfs(root->left, ans, paths);
// 回溯
paths.pop_back();
}
if (root->right)
{
paths.push_back(root->right->val);
dfs(root->right, ans, paths);
// 回溯
paths.pop_back();
}
if (root->left == nullptr && root->right == nullptr)
{
string strPath;
for (int i = 0; i < paths.size() - 1; i++)
{
strPath += to_string(paths[i]);
strPath += "->";
}
strPath += to_string(paths[paths.size() - 1]);
ans.push_back(strPath);
}
}
};
时间复杂度:O(n^2)
LeetCode 404. 左叶子之和
思路:
这题最重要的是弄清楚左叶子的概念,左叶子:节点A的左孩子不为空,且左孩子的左右孩子都为空(说明是叶子节点),那么A节点的左孩子为左叶子节点。所以左叶子并不是二叉树的左节点,不能用层序遍历的办法。列好判断左叶子节点的条件后,做法就简单了,如果为左节点,把左节点的值加上递归后计算的左子树的左叶子之和和右子树的左叶子之和,否则的话直接递归计算左右两颗子树的左叶子之和。
代码:
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
if (root == nullptr)
return 0;
if (root->left != nullptr && root->left->left == nullptr && root->left->right == nullptr)
return root->left->val + sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right);
else
return sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right);
}
};