99. 恢复二叉搜索树
中序遍历树,找到逆序的两个数,交换
有两种情况
如果是像示例1一样的,中序遍历后是3,2,1
是连续的两个逆序,那么交换第一,第三个数
如果是像示例2一样,中序遍历后是1,3,4,2
是一个逆序,那么交换这两个数即可
class Solution {
public:vector<int> vec;void traversal(TreeNode* root){if(root==nullptr)return;traversal(root->left);vec.push_back(root->val);traversal(root->right);}void recover(TreeNode* root,int count,int x,int y){if(root!=nullptr){if(root->val==x||root->val==y){if(root->val==x)root->val=y;else root->val=x;if(--count==0)return;}}if (root->left != nullptr) {recover(root->left, count, x, y);}if (root->right != nullptr) {recover(root->right, count, x, y);}return;}int index1=-1,index2=-1;void recoverTree(TreeNode* root) {traversal(root);for(int i=1;i<vec.size();i++){if(vec[i-1]>vec[i]){index2=i;if(index1==-1)index1=i-1;else break;}}cout<<index1<<index2<<endl;recover(root,2,vec[index1],vec[index2]);}
};
102.二叉树的层序遍历
模板,记住就行了
借用⼀个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑,
用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。
用result保存层序遍历的结果
用vec保存一层的结果
用que保存该层的子节点
class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {queue<TreeNode*> que;if(root!=nullptr)que.push(root);vector<vector<int>> result;while(!que.empty()){int size=que.size();vector<int> vec;for(int i=0;i<size;i++){TreeNode* node=que.front();que.pop();vec.push_back(node->val);if(node->left) que.push(node->left);if(node->right) que.push(node->right);}result.push_back(vec);}return result;}
};
103.二叉树的锯齿形层序遍历
在奇数次遍历次数时,reverse一下该层vec就行了
class Solution {
public:vector<vector<int>> zigzagLevelOrder(TreeNode* root) {queue<TreeNode*> que;int level=0;if(root!=nullptr)que.push(root);vector<vector<int>> result;while(!que.empty()){int size=que.size();vector<int> vec;for(int i=0;i<size;i++){TreeNode* node=que.front();que.pop();vec.push_back(node->val);if(node->left) que.push(node->left);if(node->right) que.push(node->right);}if(level%2)reverse(vec.begin(),vec.end());level++;result.push_back(vec);}return result;}
};
或者使用双端队列deque保存该层的节点
class Solution {
public:vector<vector<int>> zigzagLevelOrder(TreeNode* root) {queue<TreeNode*> que;if(root!=nullptr)que.push(root);vector<vector<int>> result;bool isOrderLeft = true;while(!que.empty()){int size=que.size();deque<int> level;for(int i=0;i<size;i++){TreeNode* node=que.front();que.pop();if(isOrderLeft)level.push_back(node->val);else level.push_front(node->val);if(node->left) que.push(node->left);if(node->right) que.push(node->right);}isOrderLeft=!isOrderLeft;result.push_back(vector<int>{level.begin(), level.end()});}return result;}
};
105. 从前序与中序遍历序列构造二叉树
用前序遍历的节点分割中序遍历序列
将中序遍历分为左右子树
第一步:如果数组大小为零的话,说明是空节点了。
第二步:如果不为空,那么取前序数组第一个元素作为节点元素。
第三步:找到前序数组第一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,⼀定是先
切中序数组)
第五步:切割前序数组,切成前序左数组和前序右数组
第六步:递归处理左区间和右区间
模板:
TreeNode* traversal (vector& preorder, vector& inorder) {
// 第一步
if (preorder.size() == 0) return NULL;
// 第二步:前序遍历数组第一个元素,就是当前的中间节点
int rootValue = preorder[preorder.size() - 1];
TreeNode* root = new TreeNode(rootValue);
// 叶子节点
if (preorder.size() == 1) return root;
// 第三步:找切割点
int delimiterIndex;
for (delimiterIndex = 0; delimiterIndex < inorder.size();
delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
// 第四步:切割中序数组,得到 中序左数组和中序右数组
// 第五步:切割前序数组,得到前序左数组和前序右数组
// 第六步
root->left = traversal(前序左数组, 中序左数组);
root->right = traversal(前序右数组, 中序右数组);
return root;
}
此时应该注意确定切割的标准,是左闭右开,还有左开又闭,还是左闭又闭,这个就是不变量,要在递归中保持这个不变量。
class Solution {
public:TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {// 第一步if (preorder.size() == 0) return NULL;// 第二步:前序遍历数组第一个元素,就是当前的中间节点int rootValue = preorder[0];TreeNode* root = new TreeNode(rootValue);// 叶子节点if (preorder.size() == 1) return root;// 第三步:找切割点int delimiterIndex;for (delimiterIndex = 0; delimiterIndex < inorder.size();delimiterIndex++) {if (inorder[delimiterIndex] == rootValue) break;}// 第四步:切割中序数组,得到中序左数组和中序右数组vector<int> leftInorder(inorder.begin(), inorder.begin() +
delimiterIndex);vector<int> rightInorder(inorder.begin() + delimiterIndex + 1,
inorder.end() );// 第五步:切割前序数组,得到前序左数组和前序右数组vector<int>::iterator it = preorder.begin();preorder.erase(it);vector<int> leftPreorder(preorder.begin(), preorder.begin()
+ leftInorder.size());vector<int> rightPreorder(preorder.begin() +
leftInorder.size(), preorder.end());// 第六步root->left = buildTree(leftPreorder, leftInorder);root->right = buildTree(rightPreorder, rightInorder);return root;}
};
这个代码性能并不好,因为代码里每层递归都定义了新的vector,既耗时又耗空间
可以用索引的方式重新写这个代码
class Solution {
public:TreeNode* traversal(vector<int>& preorder,int preorderBegin,int preorderEnd, vector<int>& inorder,int inorderBegin,int inorderEnd){// 第一步if (preorderBegin >= preorderEnd) return NULL;// 第二步:前序遍历数组第一个元素,就是当前的中间节点int rootValue = preorder[preorderBegin];TreeNode* root = new TreeNode(rootValue);// 叶子节点if (preorderEnd - preorderBegin == 1) return root;// 第三步:找切割点int delimiterIndex;for (delimiterIndex = 0; delimiterIndex < inorder.size();delimiterIndex++) {if (inorder[delimiterIndex] == rootValue) break;}// 第四步:切割中序数组,得到中序左数组和中序右数组int leftInorderBegin = inorderBegin;int leftInorderEnd = delimiterIndex;int rightInorderBegin = delimiterIndex + 1;int rightInorderEnd = inorderEnd;// 第五步:切割前序数组,得到前序左数组和前序右数组int leftPreorderBegin = preorderBegin+1;int leftPreorderEnd = preorderBegin + 1 + delimiterIndex -
inorderBegin;int rightPreorderBegin = preorderBegin + 1 + (delimiterIndex -
inorderBegin);int rightPreorderEnd = preorderEnd;// 第六步root->left = traversal(preorder,leftPreorderBegin,leftPreorderEnd, inorder,leftInorderBegin,leftInorderEnd);root->right = traversal(preorder,rightPreorderBegin,rightPreorderEnd, inorder,rightInorderBegin,rightInorderEnd);return root;}TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {if (preorder.size() == 0) return NULL;TreeNode* node=traversal(preorder,0,preorder.size(),inorder,0,inorder.size());return node;}
};
106.从中序与后序遍历序列构造二叉树
和上道题类似,用后序的最后一个节点分割中序序列
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:TreeNode* traversal(vector<int>& inorder,int inorderBegin,int inorderEnd,vector<int>& postorder,int postorderBegin,int postorderEnd){// 第一步if (postorderBegin >= postorderEnd) return NULL;// 第二步:后序遍历数组最后一个元素,就是当前的中间节点int rootValue = postorder[postorderEnd-1];TreeNode* root = new TreeNode(rootValue);// 叶子节点if (postorderEnd - postorderBegin == 1) return root;// 第三步:找切割点int delimiterIndex;for (delimiterIndex = 0; delimiterIndex < inorder.size();delimiterIndex++) {if (inorder[delimiterIndex] == rootValue) break;}// 第四步:切割中序数组,得到中序左数组和中序右数组int leftInorderBegin = inorderBegin;int leftInorderEnd = delimiterIndex;int rightInorderBegin = delimiterIndex + 1;int rightInorderEnd = inorderEnd;// 第五步:切割后序数组,得到后序左数组和后序右数组int leftPostorderBegin = postorderBegin;int leftPostorderEnd = postorderBegin + delimiterIndex -
inorderBegin;int rightPostorderBegin = postorderBegin + (delimiterIndex -
inorderBegin);int rightPostorderEnd = postorderEnd-1;// 第六步root->left = traversal(inorder,leftInorderBegin,leftInorderEnd, postorder,leftPostorderBegin,leftPostorderEnd);root->right = traversal(inorder,rightInorderBegin,rightInorderEnd, postorder,rightPostorderBegin,rightPostorderEnd);return root;}TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {if(inorder.size()==0)return NULL;TreeNode* node = traversal(inorder,0,inorder.size(),postorder,0,postorder.size());return node;}
};