这道题考察的是二叉树的基本操作和遍历算法的灵活运用。我们先明确几个关键概念:
二叉树是由节点组成的树形结构,每个节点最多有两个子节点(左子节点和右子节点)。题目中提到的"玩转"实际上是指对二叉树进行镜像反转(即交换每个节点的左右子树)后再进行遍历。
题目给出二叉树的中序遍历序列和前序遍历序列,要求:
输入格式:
输出格式:
解决这个问题需要掌握三个关键算法:
前序遍历的第一个元素总是树的根节点。在中序遍历中,这个根节点将序列分为左子树和右子树两部分。我们可以利用这个性质递归地构建整棵树。
具体步骤:
cpp复制TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder,
int preStart, int inStart, int inEnd,
unordered_map<int, int>& inMap) {
if (preStart >= preorder.size() || inStart > inEnd)
return nullptr;
int rootVal = preorder[preStart];
TreeNode* root = new TreeNode(rootVal);
int inRoot = inMap[rootVal];
int leftSize = inRoot - inStart;
root->left = buildTree(preorder, inorder, preStart + 1,
inStart, inRoot - 1, inMap);
root->right = buildTree(preorder, inorder, preStart + leftSize + 1,
inRoot + 1, inEnd, inMap);
return root;
}
注意:这里使用哈希表存储中序遍历的值和索引,可以将查找操作的时间复杂度从O(n)降到O(1)
镜像反转二叉树的基本思路是递归地交换每个节点的左右子树:
cpp复制void mirrorTree(TreeNode* root) {
if (!root) return;
// 交换左右子树
TreeNode* temp = root->left;
root->left = root->right;
root->right = temp;
// 递归处理子树
mirrorTree(root->left);
mirrorTree(root->right);
}
我们也可以用层序遍历的方式实现镜像反转:
cpp复制void mirrorTreeIterative(TreeNode* root) {
if (!root) return;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
TreeNode* node = q.front();
q.pop();
// 交换左右子树
TreeNode* temp = node->left;
node->left = node->right;
node->right = temp;
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
}
层序遍历(广度优先遍历)使用队列实现:
cpp复制vector<int> levelOrder(TreeNode* root) {
vector<int> result;
if (!root) return result;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
TreeNode* node = q.front();
q.pop();
result.push_back(node->val);
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
return result;
}
题目要求输出格式为空格分隔的一行数字,我们可以这样处理:
cpp复制void printLevelOrder(TreeNode* root) {
if (!root) return;
queue<TreeNode*> q;
q.push(root);
bool first = true;
while (!q.empty()) {
TreeNode* node = q.front();
q.pop();
if (first) {
cout << node->val;
first = false;
} else {
cout << " " << node->val;
}
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
cout << endl;
}
将上述各部分组合起来,完整的解题代码如下:
cpp复制#include <iostream>
#include <vector>
#include <unordered_map>
#include <queue>
using namespace std;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder,
int preStart, int inStart, int inEnd,
unordered_map<int, int>& inMap) {
if (preStart >= preorder.size() || inStart > inEnd)
return nullptr;
int rootVal = preorder[preStart];
TreeNode* root = new TreeNode(rootVal);
int inRoot = inMap[rootVal];
int leftSize = inRoot - inStart;
root->left = buildTree(preorder, inorder, preStart + 1,
inStart, inRoot - 1, inMap);
root->right = buildTree(preorder, inorder, preStart + leftSize + 1,
inRoot + 1, inEnd, inMap);
return root;
}
void mirrorTree(TreeNode* root) {
if (!root) return;
TreeNode* temp = root->left;
root->left = root->right;
root->right = temp;
mirrorTree(root->left);
mirrorTree(root->right);
}
void printLevelOrder(TreeNode* root) {
if (!root) return;
queue<TreeNode*> q;
q.push(root);
bool first = true;
while (!q.empty()) {
TreeNode* node = q.front();
q.pop();
if (first) {
cout << node->val;
first = false;
} else {
cout << " " << node->val;
}
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
cout << endl;
}
int main() {
int N;
cin >> N;
vector<int> inorder(N), preorder(N);
for (int i = 0; i < N; ++i) cin >> inorder[i];
for (int i = 0; i < N; ++i) cin >> preorder[i];
unordered_map<int, int> inMap;
for (int i = 0; i < N; ++i) {
inMap[inorder[i]] = i;
}
TreeNode* root = buildTree(preorder, inorder, 0, 0, N - 1, inMap);
mirrorTree(root);
printLevelOrder(root);
return 0;
}
构建二叉树:
镜像反转:
层序遍历:
调试建议:打印每次递归调用的参数范围,检查划分是否正确
可以不用哈希表存储中序索引,改为每次线性搜索:
cpp复制int findIndex(vector<int>& vec, int val) {
for (int i = 0; i < vec.size(); ++i) {
if (vec[i] == val) return i;
}
return -1;
}
但这样会使时间复杂度升至O(n^2),对于N≤30的题目规模仍然可接受。
类似方法可以处理:
所有递归算法都可以改为迭代实现,使用栈模拟递归过程:
cpp复制TreeNode* buildTreeIterative(vector<int>& preorder, vector<int>& inorder) {
if (preorder.empty()) return nullptr;
stack<TreeNode*> stk;
TreeNode* root = new TreeNode(preorder[0]);
stk.push(root);
int inIndex = 0;
for (int i = 1; i < preorder.size(); ++i) {
TreeNode* node = stk.top();
if (node->val != inorder[inIndex]) {
node->left = new TreeNode(preorder[i]);
stk.push(node->left);
} else {
while (!stk.empty() && stk.top()->val == inorder[inIndex]) {
node = stk.top();
stk.pop();
inIndex++;
}
node->right = new TreeNode(preorder[i]);
stk.push(node->right);
}
}
return root;
}
这种二叉树操作在以下场景中有实际应用:
理解这些基础算法有助于处理更复杂的树形结构问题。