根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
//迭代法
//逆中序:右根|左 中序:左根|右
//逆后序:根右|左 先序:根左|右
//所以,中后序和前中序构造二叉树就只有 遍历顺序 和 左右子树连接 相反即可
class Solution {//中后序构造二叉树
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if(inorder.empty())return nullptr;
TreeNode* root = new TreeNode(postorder[postorder.size()-1]);//
TreeNode* cur = nullptr;
bool flag=false;
stack<TreeNode*> s;
s.push(root);
for (int postIndex = postorder.size()-2, inIndex = inorder.size()-1; postIndex >=0; --postIndex) {//逆后序
while (s.size() && s.top()->val == inorder[inIndex]) {//逆中序
--inIndex;//
cur=s.top();
s.pop();
flag=true;
}
TreeNode* temp = new TreeNode(postorder[postIndex]);
if(flag){
cur->left=temp;//
flag=false;
}
else
s.top()->right=temp;//
s.push(temp);
}
return root;
}
};
class Solution {//前中序构造二叉树
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& preorder) {
if(inorder.empty())return nullptr;
TreeNode* root = new TreeNode(preorder[0]);//
TreeNode* cur = nullptr;
bool flag=false;
stack<TreeNode*> s;
s.push(root);
for (int preIndex = 1, inIndex = 0; preIndex < preorder.size(); ++preIndex) {//逆后序
while (s.size() && s.top()->val == inorder[inIndex]) {//逆中序
++inIndex;//
cur=s.top();
s.pop();
flag=true;
}
TreeNode* temp = new TreeNode(preorder[preIndex]);
if(flag){
cur->right=temp;//
flag=false;
}
else
s.top()->left=temp;//
s.push(temp);
}
return root;
}
};
给定一个二叉树,原地将它展开为链表。
例如,给定二叉树
1
/ \
2 5
/ \ \
3 4 6
将其展开为:
1
\
2
\
3
\
4
\
5
\
6
class Solution {
public://线索二叉树变形
void flatten(TreeNode* root) {//morris线索二叉树变形,线索二叉树代码框架在下下面
TreeNode *cur=root,*temp=nullptr;
while(cur){
temp=cur->left;
if(temp){
while(temp->right)
temp=temp->right;
if(!temp->right){
temp->right=cur->right;//
cur->right=cur->left;//
cur->left=nullptr;//
cur=cur->right;//
continue;
}
}
cur=cur->right;
}
}
/*第一遍思路,做不出来
TreeNode* helper(TreeNode* root){
if(root->left&&root->right){
TreeNode* temp=helper(root->left);
temp->right=root->right;
root->right=root->left;
return helper(temp->right);
}
else if(root->left){
root->right=root->left;
return helper(root->right);
}
else if(root->right)
return helper(root->right);
else
return root;
}*/
};
morris线索二叉树
morris二叉树遍历:时间复杂度O(n),空间复杂度O(1)
1)记忆口诀:循环当前,左右到底,右子有无,当前左右,后前前中
后左尾头,右子反转,next开头,首尾相接,遍历反转
2) morris遍历时,此时若还有线索未解锁则不能直接返回函数,否则报错
3)前中后代码框架
TreeNode *cur=root,*temp=nullptr;
while(cur){
temp=cur->left;
if(temp){
while(temp->right&&temp->right!=cur)
temp=temp->right;
if(temp->right){
temp->right=nullptr;
//后序节点处理
}
else{
temp->right=cur;
//前序节点处理
cur=cur->left;
continue;
}
}
else
//前序节点处理
//中序节点处理
cur=cur->right;
}
4)中序
void InOrder(TreeNode* root){//morris中序(左,根,右)
TreeNode *cur=root,*pre=nullptr,*temp=nullptr;
while(cur){
temp=cur->left;
if(temp){
while(temp->right&&temp->right!=cur)
temp=temp->right;
if(temp->right)
temp->right=nullptr;
else{
temp->right=cur;
cur=cur->left;
continue;
}
}
operate(cur),pre=cur;//如果需要用到前驱节点则需定义pre,否则不用
cur=cur->right;
}
}
5)前序
void PreOrder(TreeNode* root){//morris前序(根,左,右)
TreeNode *cur=root,*pre=nullptr,*temp=nullptr;
while(cur){
temp=cur->left;
if(temp){
while(temp->right&&temp->right!=cur)
temp=temp->right;
if(temp->right)
temp->right=nullptr;
else{
temp->right=cur;
operate(cur),pre=cur;//如果需要用到前驱节点则需定义pre,否则不用
cur=cur->left;
continue;
}
}
else
operate(cur),pre=cur;//如果需要用到前驱节点则需定义pre,否则不用
cur=cur->right;
}
}
6)后序
void PostOrder(TreeNode* root){//morris前序(左,右, 根)
TreeNode *cur=root,*pre=nullptr,*temp=nullptr;
while(cur){
temp=cur->left;
if(temp){
while(temp->right&&temp->right!=cur)
temp=temp->right;
if(temp->right){
temp->right=nullptr;
PostHelper(cur->left);
}
else{
temp->right=cur;
cur=cur->left;
continue;
}
}
cur=cur->right;
}
operate(head)
}
void PostHelper(TreeNode* root){
//1 链表(右)逆序,头节点为root
TreeNode *cur=root,*pre=nullptr,*next=nullptr;
while(cur){//next开头,首位相接,方便记忆,如下
next=cur->right;//next=cur->right=pre=cur=next
cur->right=pre;
pre=cur;
cur=next;
}
//2 右边界逆序遍历
cur=pre;//此时头节点为pre
while(cur){
operate(cur);
cur=cur->right;
}
//3 链表(右)逆序,头节点为pre
cur=pre,pre=nullptr,next=nullptr;
while(cur){
next=cur->right;
cur->right=pre;
pre=cur;
cur=next;
}
}
递归/迭代+后序+pre节点
class Solution {
public:
TreeNode* pre=nullptr;
void flatten(TreeNode* root) {
//递归/迭代+变形后序(右,左,根)+ pre节点
if(!root)return;
flatten(root->right);
flatten(root->left);
root->right=pre;
root->left=nullptr;
pre=root;
}
}
总结(遇到二叉树问题):
1考虑前中后序遍历
2考虑前中后序遍历+pre前驱节点
3考虑前中后 逆序遍历(+pre),比如逆前序:根左右->右左根
4考虑前中后 变序遍历(+pre),比如变前序:根左右->根右左
5考虑递归<迭代(时间空间都O(n))<morris(空间O(1),但不在遍历中途必须线索都解锁了才能返回,否则必须遍历到结束才能返回)
给定一个非空二叉树,返回其最大路径和。
本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。
示例 1:
输入: [1,2,3]
1
/ \
2 3
输出: 6
示例 2:
输入: [-10,9,20,null,null,15,7]
-10
/ \
9 20
/ \
15 7
输出: 42
class Solution {
public:
long long path=INT_MIN,curmaxpath=LLONG_MIN;
int maxPathSum(TreeNode* root) {
helper(root);
return curmaxpath;
}
int helper(TreeNode* root){
if(!root)return 0;
int l=max(helper(root->left),0);//l=helper(root->left) 易错!!!
int r=max(helper(root->right),0);//
path=root->val+l+r;
curmaxpath=max(path,curmaxpath);
return max(l,r)+root->val;
}
};