这个问题的思路就是,通过后序遍历找到头结点,然后在中序遍历中划分子树, 再对子树执行相同的操作,直至子树为空。
而我之前的方法是在细节上比较粗(wu)暴(nao) 因此效率过于低下。
更详细的过程就是,根据后序遍历找到头结点,再在中序遍历中划分子树,而根据中序遍历中划分的子树大小,又可以作为偏移量来对后序遍历中的结点做划分。然后再对这一子树执行之前的操作。
我的代码是:
TreeNode* buildTree (vector<int> &inorder, vector<int> &postorder) { if (inorder.empty ()) { return nullptr; } unordered_map<int, INTVECIT> inItDic; unordered_map<int, INTVECIT> postItDic; for (auto it = inorder.begin(); it != inorder.end(); ++it){ inItDic[*it] = it; } for (auto it = postorder.begin(); it != postorder.end(); ++it){ postItDic[*it] = it; } auto rootVal = postorder.back (); auto root = new TreeNode (rootVal); auto rootIt = inItDic[rootVal]; function<void(TreeNode*, INTVECIT, INTVECIT)> build; build = [&] (TreeNode *subRoot, INTVECIT begin, INTVECIT end) { if (begin == end) { return; } set<INTVECIT> weights; for (auto it = begin; it != end; ++it) { weights.insert (postItDic[*it]); } auto newSubRootVal = **weights.crbegin (); auto newSubRoot = new TreeNode (newSubRootVal); if (newSubRootVal < subRoot->val) { subRoot->left = newSubRoot; } else { subRoot->right = newSubRoot; } auto newSubRootIt = inItDic[newSubRootVal]; build (newSubRoot, begin, newSubRootIt); build (newSubRoot, newSubRootIt + 1, end); }; build (root, inorder.begin(), rootIt); build (root, rootIt + 1, inorder.end()); return root; }
运行时间多久? 2.67s 我可是自认挺好了, 毕竟我刚写好代码的时候可是运行了 20s+
可是 leetcode 并不认同,我就崩溃了,卧槽这都超时?两秒半也超时? 你特么在逗我!
直到在知乎上,一位好心前辈给了我一个解答,还就在我的代码基础上改的:
TreeNode* buildTree (vector<int> &inorder, vector<int> &postorder) { using IndexType = vector<int>::size_type; if (inorder.empty () || postorder.empty() || inorder.size() != postorder.size()) { return nullptr; } unordered_map<int, int> inIndexDic; for (auto i = 0; i < inorder.size(); ++i) { inIndexDic[inorder[i]] = i; } function<TreeNode*(IndexType, IndexType, IndexType, IndexType)> build; build = [&] (IndexType inBegin, IndexType inEnd, IndexType postBegin, IndexType postEnd) -> TreeNode* { if (inBegin == inEnd) { return nullptr; } IndexType newRootIndex = inIndexDic[postorder[postEnd - 1]]; IndexType leftSize = newRootIndex - inBegin; IndexType rightSize = inEnd - newRootIndex - 1; auto newRoot = new TreeNode(inorder[newRootIndex]); newRoot->left = build(inBegin, newRootIndex, postBegin, postBegin + leftSize); newRoot->right = build(newRootIndex + 1, inEnd, postBegin + leftSize, postBegin + leftSize + rightSize); return newRoot; }; return build(0, inorder.size(), 0, postorder.size()); }
用了多少时间?
0.002547s
我还是太年轻。
附:我再次重写的版本
TreeNode* buildTree(vector<int> &inorder, vector<int> &postorder){ if (inorder.empty() || postorder.empty() || inorder.size() != postorder.size()){ return nullptr; } using IndexType = vector<int>::size_type; unordered_map<int, IndexType> inIndexDic; auto inLength = inorder.size(); for (decltype(inLength) i = 0; i < inLength; ++i){ inIndexDic[inorder[i]] = i; } function<TreeNode*(IndexType, IndexType, IndexType, IndexType)> build; build = [&](IndexType inBegin, IndexType inEnd, IndexType postBegin, IndexType postEnd)->TreeNode* { if (inBegin == inEnd){ return nullptr; } auto newRootIndex = inIndexDic[postorder[postEnd -1]]; auto newRoot = new TreeNode(inorder[newRootIndex]); auto leftSubTreeSize = newRootIndex - inBegin; auto rightSubTreeSize = inEnd - newRootIndex - 1; newRoot->left = build(inBegin, newRootIndex, postBegin, postBegin + leftSubTreeSize); newRoot->right = build(newRootIndex + 1, inEnd, postBegin + leftSubTreeSize, postBegin + leftSubTreeSize + rightSubTreeSize); return newRoot; }; return build(0, inLength, 0, postorder.size()); }