1.AVLTree判断
110. 平衡二叉树
后序遍历的强化理解:
所谓后续遍历,不仅仅是一种遍历,其实它是完成了所有左右子树的递归。后续遍历能将自己所求的值返回给上层节点。这在比较中很关键,举个例子,我们能得到下边节点返回给上面节点的层数,那么就能进行高度的比较。
本题其实也是一样的思路:
1.我想设计一个算法,使得每一个节点的高度,那么后续遍历能完成该任务。是否平衡的比较落在左右节点之差上,最后如果不是AVL树,那我们返回-1。
2.返回值为int型,因为我们需要统计每一层的节点高度;传入的参数为树的节点
3.结束递归依据为root是否走到nullptr,如果根节点为空,此时走到底部,返回给上层为0,因为该位置没有节点
4.我们使用后续遍历,那么对应的定义left变量接收左边的高度,并且如果左边高度为-1,说明此时下面传回的信息是“已经不是平衡二叉树”,那么后续其实已经不需要操作了,那么我们直接返回-1,往上告知该树不是平衡二叉树;对应的定义right变量接收右边的高度,遇到-1的情况与左子树一样处理。
5.最后我们执行中间操作:如果左边-右边的绝对值绝对高度差大于1,说明此时不平衡,直接返回-1;如果不是,那么我们要返回上层的高度,所以我们要比较左右节点高度谁大,将大的值进行加一再返回,加一操作是因为上层节点也是一个高度,所以上层得到自己的高度是下面高度加上自己节点的高度。
class Solution {
public:
int _isBalancedR(TreeNode* root)
{
if(root==nullptr)
return 0;
int left = _isBalancedR(root->left);
if(left==-1)
return -1;
int right = _isBalancedR(root->right);
if(right==-1)
return -1;
int ret;
if(abs(left-right)>1)
return -1;
return ret=(left>right)?left+1:right+1;
}
bool isBalanced(TreeNode* root) {
if(_isBalancedR(root)==-1)
return false;
return true;
}
};
2.二叉树的所有路径
257. 二叉树的所有路径
大体思路:我想通过传递string的变量,使得每一层都有不同的string继承上面传来的路径
1.实现该函数传入的参数为:根节点,引用参数vector<string> vs和string s,由于我们只需要对s收获的路径存储到引用vs中,所以不需要进行什么传回操作,因此我们函数返回void
2.返回条件,这题与之前的最小深度思路有点重合:”就是如果一个节点左右有一个节点为空,但是另一个不为空,此时往空节点那里走是不会触发存储条件的!!!这点很重要,是树的减枝操作“;所以我们不仅要判断节点是否为空,还要判断节点的左右节点是否为空。因此返回条件有两种:一、如果当前节点不为空,但是左右节点为空,说明该节点为叶子节点,那么我们需要把这个路径存储下来,再返回 二、如果当前节点为空,此时已经过了条件一的判断,说明这种路径是需要被减枝的,所以直接返回即可
3.我们使用的是前序遍历,因为这样我们才能得到遍历的叶子节点数据,那操作很简单:就是将root的val存储到s中,随后左右遍历
4.s中存储数据需要注意,如果是中间操作,那么我们要加上题目要求的”->“标记,如果在叶子节点,那么说明此时不需要加”->“标记
class Solution {
public:
void _GetTreePathR(TreeNode* root,vector<string>& vs,string s)
{
if(root&&root->left==nullptr&&root->right==nullptr)
{
s+=(to_string(root->val));
vs.push_back(s);
return;
}
if(root==nullptr)
return;
s+=(to_string(root->val)+"->");
_GetTreePathR(root->left,vs,s);
_GetTreePathR(root->right,vs,s);
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> vs;
string s;
_GetTreePathR(root,vs,s);
return vs;
}
};
这种通过string临时遍历保存每一层的操作确实简单,但是它浪费空间啊,每一层都保存一个string,要是节点多,爆内存是迟早的事情。所以优化的目标就是把string也变成引用参数,这样我们开辟的就只有一个string了。不过此时对应的就是要把sting往上返回时,减去一些数据。
无非就是用一个tmp存储,在走到vs存储后,将s剪掉后面的数据;当一层遍历结束,返回上层时,把对应的数据删除
class Solution {
public:
void _GetTreePathR(TreeNode* root,vector<string>& vs,string& s)
{
if(root&&root->left==nullptr&&root->right==nullptr)
{
string tmp = to_string(root->val);
s+=(tmp);
vs.push_back(s);
s.erase(s.end()-tmp.size(),s.end());
return;
}
if(root==nullptr)
return;
string tmp = to_string(root->val)+"->";
s+=(tmp);
_GetTreePathR(root->left,vs,s);
_GetTreePathR(root->right,vs,s);
s.erase(s.end()-tmp.size(),s.end());
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> vs;
string s;
_GetTreePathR(root,vs,s);
return vs;
}
};
3.左叶子之和
404. 左叶子之和
这道题所说的左叶子特征:
1.该节点没有左右节点
2.该节点为父节点的左节点
所以描述成代码就是:当前位置不为空,当前位置的左节点不为空,当前位置的左节点没有子节点
class Solution {
public:
void _GetSumR(TreeNode* root,int& sum)
{
if(root&&root->left&&!(root->left->left)&&!(root->left->right))
sum+=root->left->val;
if(root==nullptr)
return;
_GetSumR(root->left,sum);
_GetSumR(root->right,sum);
}
int sumOfLeftLeaves(TreeNode* root) {
int sum = 0;
_GetSumR(root,sum);
return sum;
}
};