题目大意:
给定一棵树的结点个数n,以及它的前序遍历和后序遍历,输出它的中序遍历;
如果中序遍历不唯一就输出No,且输出其中一个中序即可,如果中序遍历唯一就输出Yes,并输出它的中序
思路:(转载)
先序+后序 无法判断二叉树的唯一性
- 先序第一个节点是根节点,紧接着第二个节点是根节点的左节点还是右节点?
- 在后序中查找 先序中的第二个节点,
- 如果后序中的该位置 到 最后(也就是后序中根节点位置) 还有其他数的话,可以判断,先序中第二个节点肯定左节点(反证法。。。)
- 当中间没有数的时候,就不确定了
例如:
前序序列:1 2 3 4 后序序列:2 4 3 1 1 为 根,2 接着,2在后序中,与1隔着两个数,所以2一定是1的左节点; 3,4成为1的右子树节点
#include<bits/stdc++.h> using namespace std; int n; bool isUnique = true; vector<int> preOrder, in, postOrder; struct Node { int val; Node* lchild, *rchild; Node(int _val = -1){ val = _val; lchild = NULL; rchild = NULL; } }; Node* Create(int preL, int preR, int postL, int postR) { Node* root = new Node(preOrder[preL]); if (preL == preR) return root; int k; for (k = postL; k < postR; k++){ // 后序找 pre[preL + 1] if (postOrder[k] == preOrder[preL + 1]) break; } // 在后序中查找 先序中的第二个节点 // 如果后序中的该位置 到 最后(也就是后序中根节点位置) 还有其他数的话, // 可以判断,先序中第二个节点肯定左节点(反证法。。。) if (postR - k - 1 > 0){ int numLeft = k - postL + 1; root->lchild = Create(preL + 1, preL + numLeft, postL, k); root->rchild = Create(preL + 1 + numLeft, preR, k + 1, postR - 1); } else { isUnique = false; //假定第二个节点是根节点的右节点 root->rchild = Create(preL + 1, preR, postL, postR - 1); } return root; } void inOrder(Node* root){ if (root != NULL){ inOrder(root->lchild); in.push_back(root->val); inOrder(root->rchild); } } int main() { scanf("%d", &n); preOrder.resize(n); postOrder.resize(n); for (int i = 0; i < n; i++) scanf("%d", &preOrder[i]); for (int i = 0; i < n; i++) scanf("%d", &postOrder[i]); Node* root = Create(0, n - 1, 0, n - 1); inOrder(root); printf("%s %d", isUnique == true ? "Yes" : "No", in[0]); for (int i = 1; i<n; i++) printf(" %d", in[i]); printf(" "); return 0; }