思路的重点是判断完一个子树是否是平衡二叉树时如何返回结果。开始想的是把递归的返回值类型设置为bool,但是这样就无法返回子节点的高度信息,最后还是没想明白。
思路:不断获取子节点的高度,如果两侧节点高度差大于1,说明该节点代表的子树是非平衡二叉树,返回-1即可。最后递归的结果如果是-1,说明是非平衡二叉树。
// 计算当前节点高度,
// 如果左右子树的高度差大于1说明当前子树是非平衡二叉树,直接返回-1
int getDepth(TreeNode* cur) {
if (!cur)
return 0;
int leftDepth = getDepth(cur->left);
int rightDepth = getDepth(cur->right);
if (leftDepth == -1 || rightDepth == -1)
return -1;
int diff = abs(leftDepth - rightDepth);
return (diff > 1) ? -1 : std::max(leftDepth, rightDepth) + 1;
}
bool isBalanced(TreeNode* root) {
return getDepth(root) > -1;
}
最开始想到的是用前序遍历,但是返回值类型与参数没有想明白,最开始的声明形式为vector
递归写法:
思路:父节点不断更新当前路径,并将路径传递给子节点,当子节点为叶节点时向结果数组中添加当前路径
· 返回值类型:void,不需要返回值,将结果记录在引用维护的结果数组中即可
· 传入参数:
TreeNode* cur:当前节点的指针
string path:父节点的路径
vector
&ans:结果数组,受引用维护,在全部的递归过程中是唯一的 · 单层递归逻辑——前序遍历:
中:更新当前节点,判断当前节点是否是叶子节点,如果是则将当前路径加入结果数组
左:递归访问左孩子
右:递归访问右孩子
void getPaths(TreeNode* cur, string path, vector &ans) {
if (!cur)
return;
// 中,更新path,如果当前节点是叶子节点将path加入结果数组并返回
// 更新path
if (path == "")
// 根节点的path字符串需要特殊处理
path = std::to_string(cur->val);
else
path = path + "->" + std::to_string(cur->val);
if (!cur->left && !cur->right) {
ans.push_back(path);
return;
}
// 左
getPaths(cur->left, path, ans);
// 右
getPaths(cur->right, path, ans);
return;
}
vector binaryTreePaths0(TreeNode* root) {
vector ans;
getPaths(root, "", ans);
return ans;
}
迭代写法:
由于需要获取节点对应的路径,所以要多建一个栈,同步保存对应节点的路径
vector binaryTreePaths(TreeNode* root) {
vector ans;
stack st;
stack pathSt; // 路径也要使用栈保存,从而与节点同步
TreeNode* cur;
string path;
if (root) {
st.push(root);
pathSt.push(std::to_string(root->val));
}
while (!st.empty()) {
cur = st.top();
path = pathSt.top();
st.pop();
pathSt.pop();
// 中
if (!cur->left && !cur->right) {
ans.push_back(path);
}
// 左
if (cur->left) {
st.push(cur->left);
pathSt.push(path + "->" + std::to_string(cur->left->val));
}
// 右
if (cur->right) {
st.push(cur->right);
pathSt.push(path + "->" + std::to_string(cur->right->val));
}
}
return ans;
}
(感觉卡哥的写法有些繁琐了,虽然节省了一个参数需要的空间,但不是很好理解)
思路:与257有点类似,使用一个引用维护结果,当节点是左叶子时使用节点值对结果进行更新
· 返回值类型:void,不需要返回值,将结果使用一个引用进行维护即可
· 传入参数:
TreeNode* cur:当前节点的指针
bool isLeft:判断该节点是否为左节点的布尔值
int &ans:所有左叶子的和,受引用维护,在全部递归过程中是唯一的
· 单层递归逻辑——前序遍历:
中:判断当前节点是否是左叶子,如果是则更新ans的值
左:递归访问左孩子,isLeft传入true
右:递归访问右孩子,isLeft传入false
void traversal(TreeNode* cur, bool isLeft, int& sum) {
if (!cur)
return;
// 中
if (isLeft && !cur->left && !cur->right) {
sum += cur->val;
return;
}
// 左
traversal(cur->left, true, sum);
// 右
traversal(cur->right, false, sum);
}
int sumOfLeftLeaves(TreeNode* root) {
int sum = 0;
traversal(root, false, sum);
return sum;
}
递归:
1、对于需要在递归过程中保持唯一性的变量(如最后的结果),可以使用引用维护(效果与使用一个全局变量维护相同)
2、关于递归顺序:
· 当子节点需要父节点信息的时候使用前序遍历,如:
257子节点需要父节点路径
404子节点需要父节点判断该子节点是不是左节点
· 当父节点需要子节点信息时使用后序遍历,如:
104求最大深度,父节点需要子节点的高度信息
迭代:
当需要该节点除成员属性以外的信息(如节点路径,是否是左节点)时,可以多建几个栈同步保持节点信息。