题意:
由连续两行来表示一棵二叉树, 第一行为中序遍历, 第二行为后序遍历; 要求输出从根节点到叶子节点的各个路径中, 和最小的路径的叶子节点的值; 如果存在多个最小和, 则输出值最小的叶子节点.思路:
1. 根据输入的中序遍历和后序遍历创建树:(1). 中序:左根右;(2). 后序:左右根;(3). 由上可以看到,从后序遍历最后开始,找到“根”,然后在中序中找到“根”,其左边就是左子树,右边就是右子树.依此递归, 可建树.2. 从左/右子树递归寻找最小路径和, 为了确保当路径和相等时, 取最小叶节点, 需要把叶子节点的值也和一起返回.
要点:
1. 使用 istringstream 读取 string 中的各个 int, 速度并不比自己解析字符串, 然后 atoi 慢太多, 如果提交时提示 Time limit exceeded, 应该是别的地方出了问题, 无需在这里优化太多.2. vector back 函数返回最后一个值.题目:
代码:
# include# include # include # include # include # include # include # include # include # include using namespace std;// 读入两行,第一行中序,第二行后序遍历,// 要求找到从根节点到叶节点路径和最小的叶节点,若有多个最小和,则输出最小的叶节点class Node {public: Node(int n, Node* left, Node* right): n_(n), left_(left), right_(right){} int n_; Node* left_; Node* right_;};// 找到 n 在 vt[begin, end) 中的下标,若找不到,则返回 end// 为了保证重复节点出现时,找到的下标是靠后的节点,这里从后往前找int getIndex(const vector & vt, int begin, int end, int n) { for (int i=end-1; i>=begin; i--) { if (vt[i] == n) return i; } return end;}// 根据中序与后序遍历创建树// 中序:左根右// 后序:左右根// 算法:由上可以看到,从后序最后开始遍历,找到“根”,然后在中序中找到“根”,// 其左边就是左子树,右边就是右子树Node* buildTree(const vector & inOrder, int inBegin, int inEnd, const vector & postOrder, int postBegin, int postEnd) { if (inBegin>=inEnd || postBegin>=postEnd) return NULL; // 后序的最后一位就是根节点 int n = postOrder[postEnd-1]; int rootIndex = getIndex(inOrder, inBegin, inEnd, n); int leftLength = rootIndex - inBegin; Node* left = buildTree(inOrder, inBegin, rootIndex, postOrder, postBegin, postBegin + leftLength); Node* right = buildTree(inOrder, rootIndex + 1, inEnd, postOrder, postBegin + leftLength, postEnd - 1); Node* root = new Node(n, left, right); return root;}// 释放树空间void freeTree(Node* root) { if (root == NULL) return; freeTree(root->left_); freeTree(root->right_); delete root;}// 找到从根节点到叶节点路径和最小的叶节点,若有多个最小和,则输出最小的叶节点// 返回值,first 表示当前最小和,second 表示对应叶节点的值pair getLeastLeafNode(Node* root) { if (root->left_ == NULL && root->right_ == NULL) { return make_pair(root->n_, root->n_); } pair least; if (root->left_ == NULL && root->right_ != NULL) { least = getLeastLeafNode(root->right_); } else if (root->left_ != NULL && root->right_ == NULL) { least = getLeastLeafNode(root->left_); } else { pair left = getLeastLeafNode(root->left_); pair right = getLeastLeafNode(root->right_); if (left.first < right.first) { least = left; } else if (left.first > right.first) { least = right; } else { // left.first == right.first least = left.second < right.second ? left : right; } } return make_pair(least.first + root->n_, least.second);}int main(int argc, char const *argv[]){ #ifndef ONLINE_JUDGE freopen("548_i.txt", "r", stdin); freopen("uva_o.txt", "w", stdout); #endif // 输入 string inLine; string postLine; while (getline(cin, inLine) && getline(cin, postLine)) { int n; vector inOrder, postOrder; // 读取一行中的各个 int // 中序 istringstream issIn(inLine); while (issIn >> n) inOrder.push_back(n); // 后序 istringstream issPost(postLine); while (issPost >> n) postOrder.push_back(n); // 建树,分析,输出 Node* root = buildTree(inOrder, 0, inOrder.size(), postOrder, 0, postOrder.size()); cout << getLeastLeafNode(root).second << endl; freeTree(root); } return 0;}
环境: C++ 4.5.3 - GNU C++ Compiler with options: -lm -lcrypt -O2 -pipe -DONLINE_JUDGE
改进:
参考:
这里提到给定的数据时有重复的节点, 那么你在中序序列中应找最靠后的那个节点, 因为后序遍历是 左右中, 只有这样才能正确的遍历这棵树.