Title: [LeetCode] 145. Binary Tree Postorder Traversal · Issue #145 · grandyang/leetcode · GitHub
Open Graph Title: [LeetCode] 145. Binary Tree Postorder Traversal · Issue #145 · grandyang/leetcode
X Title: [LeetCode] 145. Binary Tree Postorder Traversal · Issue #145 · grandyang/leetcode
Description: Given a binary tree, return the postorder traversal of its nodes' values. For example: Given binary tree {1,#,2,3}, 1 \ 2 / 3 return [3,2,1]. Note: Recursive solution is trivial, could you do it iteratively? 经典题目,求二叉树的后序遍历的非递归方法,跟前序,中序,层...
Open Graph Description: Given a binary tree, return the postorder traversal of its nodes' values. For example: Given binary tree {1,#,2,3}, 1 \ 2 / 3 return [3,2,1]. Note: Recursive solution is trivial, could you do it it...
X Description: Given a binary tree, return the postorder traversal of its nodes' values. For example: Given binary tree {1,#,2,3}, 1 \ 2 / 3 return [3,2,1]. Note: Recursive solution is trivial, could you do i...
Opengraph URL: https://github.com/grandyang/leetcode/issues/145
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"[LeetCode] 145. Binary Tree Postorder Traversal","articleBody":" \n\nGiven a binary tree, return the _postorder_ traversal of its nodes' values.\n\nFor example: \nGiven binary tree `{1,#,2,3}`, \n\n \n \n 1\n \\\n 2\n /\n 3\n \n\nreturn `[3,2,1]`.\n\n**Note:** Recursive solution is trivial, could you do it iteratively?\n\n \n\n经典题目,求二叉树的后序遍历的非递归方法,跟前序,中序,层序一样都需要用到栈,后序的顺序是左-右-根,所以当一个结点值被取出来时,它的左右子结点要么不存在,要么已经被访问过了。先将根结点压入栈,然后定义一个辅助结点 head,while 循环的条件是栈不为空,在循环中,首先将栈顶结点t取出来,如果栈顶结点没有左右子结点,或者其左子结点是 head,或者其右子结点是 head 的情况下。将栈顶结点值加入结果 res 中,并将栈顶元素移出栈,然后将 head 指向栈顶元素;否则的话就看如果右子结点不为空,将其加入栈,再看左子结点不为空的话,就加入栈,注意这里先右后左的顺序是因为栈的后入先出的特点,可以使得左子结点先被处理。下面来看为什么是这三个条件呢,首先如果栈顶元素如果没有左右子结点的话,说明其是叶结点,而且入栈顺序保证了左子结点先被处理,所以此时的结点值就可以直接加入结果 res 了,然后移出栈,将 head 指向这个叶结点,这样的话 head 每次就是指向前一个处理过并且加入结果 res 的结点,那么如果栈顶结点的左子结点或者右子结点是 head 的话,说明其子结点已经加入结果 res 了,那么就可以处理当前结点了。\n\n看到这里,大家可能对 head 的作用,以及为何要初始化为 root,还不是很清楚,这里再解释一下。head 是指向上一个被遍历完成的结点,由于后序遍历的顺序是左-右-根,所以一定会一直将结点压入栈,一直到把最左子结点(或是最左子结点的最右子结点)压入栈后,开始进行处理。一旦开始处理了,head 就会被重新赋值。所以 head 初始化值并没有太大的影响,唯一要注意的是不能初始化为空,因为在判断是否打印出当前结点时除了判断是否是叶结点,还要看 head 是否指向其左右子结点,如果 head 指向左子结点,那么右子结点一定为空,因为入栈顺序是根-右-左,不存在右子结点还没处理,就直接去处理根结点了的情况。若 head 指向右子结点,则是正常的左-右-根的处理顺序。那么回过头来在看,若 head 初始化为空,且此时正好左子结点不存在,那么在压入根结点时,head 和左子结点相等就成立了,此时就直接打印根结点了,明显是错的。所以 head 只要不初始化为空,一切都好说,甚至可以新建一个结点也没问题。将 head 初始化为 root,也可以,就算只有一个 root 结点,那么在判定叶结点时就将 root 打印了,然后就跳出 while 循环了,也不会出错。代码如下:\n\n \n\n解法一:\n \n \n class Solution {\n public:\n vector\u003cint\u003e postorderTraversal(TreeNode* root) {\n if (!root) return {};\n vector\u003cint\u003e res;\n stack\u003cTreeNode*\u003e s{{root}};\n TreeNode *head = root;\n while (!s.empty()) {\n TreeNode *t = s.top();\n if ((!t-\u003eleft \u0026\u0026 !t-\u003eright) || t-\u003eleft == head || t-\u003eright == head) {\n res.push_back(t-\u003eval);\n s.pop();\n head = t;\n } else {\n if (t-\u003eright) s.push(t-\u003eright);\n if (t-\u003eleft) s.push(t-\u003eleft);\n }\n }\n return res;\n }\n };\n\n \n\n由于后序遍历的顺序是左-右-根,而先序遍历的顺序是根-左-右,二者其实还是很相近的,可以先在先序遍历的方法上做些小改动,使其遍历顺序变为根-右-左,然后翻转一下,就是左-右-根啦,翻转的方法我们使用反向Q,哦不,是反向加入结果 res,每次都在结果 res 的开头加入结点值,而改变先序遍历的顺序就只要该遍历一下入栈顺序,先左后右,这样出栈处理的时候就是先右后左啦,参见代码如下:\n\n \n\n解法二:\n \n \n class Solution {\n public:\n vector\u003cint\u003e postorderTraversal(TreeNode* root) {\n if (!root) return {};\n vector\u003cint\u003e res;\n stack\u003cTreeNode*\u003e s{{root}};\n while (!s.empty()) {\n TreeNode *t = s.top(); s.pop();\n res.insert(res.begin(), t-\u003eval);\n if (t-\u003eleft) s.push(t-\u003eleft);\n if (t-\u003eright) s.push(t-\u003eright);\n }\n return res;\n }\n };\n\n \n\n那么在 [Binary Tree Preorder Traversal](http://www.cnblogs.com/grandyang/p/4146981.html) 中的解法二也可以改动一下变成后序遍历,改动的思路跟上面的解法一样,都是先将先序遍历的根-左-右顺序变为根-右-左,再翻转变为后序遍历的左-右-根,翻转还是改变结果 res 的加入顺序,然后把更新辅助结点p的左右顺序换一下即可,代码如下:\n\n \n\n解法三:\n \n \n class Solution {\n public:\n vector\u003cint\u003e postorderTraversal(TreeNode* root) {\n vector\u003cint\u003e res;\n stack\u003cTreeNode*\u003e s;\n TreeNode *p = root;\n while (!s.empty() || p) {\n if (p) {\n s.push(p);\n res.insert(res.begin(), p-\u003eval);\n p = p-\u003eright;\n } else {\n TreeNode *t = s.top(); s.pop();\n p = t-\u003eleft;\n }\n }\n return res;\n }\n };\n\n \n\n论坛上还有一种双栈的解法,其实本质上跟解法二没什么区别,都是利用了改变先序遍历的顺序来实现后序遍历的,参见代码如下:\n\n \n\n解法四:\n \n \n class Solution {\n public:\n vector\u003cint\u003e postorderTraversal(TreeNode* root) {\n if (!root) return {};\n vector\u003cint\u003e res;\n stack\u003cTreeNode*\u003e s1, s2;\n s1.push(root);\n while (!s1.empty()) {\n TreeNode *t = s1.top(); s1.pop();\n s2.push(t);\n if (t-\u003eleft) s1.push(t-\u003eleft);\n if (t-\u003eright) s1.push(t-\u003eright);\n }\n while (!s2.empty()) {\n res.push_back(s2.top()-\u003eval); s2.pop();\n }\n return res;\n }\n };\n\n \n\nGithub 同步地址:\n\n\u003chttps://github.com/grandyang/leetcode/issues/145\u003e\n\n \n\n类似题目:\n\n[Binary Tree Preorder Traversal](http://www.cnblogs.com/grandyang/p/4146981.html)\n\n[Binary Tree Inorder Traversal](http://www.cnblogs.com/grandyang/p/4297300.html)\n\n[Binary Tree Level Order Traversal](http://www.cnblogs.com/grandyang/p/4051321.html)\n\n \n\n参考资料:\n\n\u003chttps://leetcode.com/problems/binary-tree-postorder-traversal/\u003e\n\n\u003chttps://leetcode.com/problems/binary-tree-postorder-traversal/discuss/45803/java-solution-using-two-stacks\u003e\n\n\u003chttps://leetcode.com/problems/binary-tree-postorder-traversal/discuss/45551/preorder-inorder-and-postorder-iteratively-summarization\u003e\n\n\u003chttps://leetcode.com/problems/binary-tree-postorder-traversal/discuss/45621/preorder-inorder-and-postorder-traversal-iterative-java-solution\u003e\n\n \n\n[LeetCode All in One 题目讲解汇总(持续更新中...)](http://www.cnblogs.com/grandyang/p/4606334.html)\n","author":{"url":"https://github.com/grandyang","@type":"Person","name":"grandyang"},"datePublished":"2019-05-30T16:15:57.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/145/leetcode/issues/145"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:b1ceed32-b68d-1bab-bf18-dddc93c647e0 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 8684:22A813:3396051:448682E:6A654F45 |
| html-safe-nonce | 638df9704e6a86c87da44edc16a922dc79594ab729feca7a3240150504c0fa9d |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4Njg0OjIyQTgxMzozMzk2MDUxOjQ0ODY4MkU6NkE2NTRGNDUiLCJ2aXNpdG9yX2lkIjoiODk0MzM0MTgyNDUwMzAwOTA5MyIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 33cf8e5a806c00ae5a210ea1fed7aaec192b0c8c3ccf3efce52ce5cd2bdbf9eb |
| hovercard-subject-tag | issue:450387150 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/grandyang/leetcode/145/issue_layout |
| twitter:image | https://opengraph.githubassets.com/2569ff0381e44c86f64e7ec3e15ce76fa2c76f39c2a6789caf60a0512ee3cbc1/grandyang/leetcode/issues/145 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/2569ff0381e44c86f64e7ec3e15ce76fa2c76f39c2a6789caf60a0512ee3cbc1/grandyang/leetcode/issues/145 |
| og:image:alt | Given a binary tree, return the postorder traversal of its nodes' values. For example: Given binary tree {1,#,2,3}, 1 \ 2 / 3 return [3,2,1]. Note: Recursive solution is trivial, could you do it it... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | grandyang |
| hostname | github.com |
| expected-hostname | github.com |
| None | 52c76df668885aaff23b50bdca1fa1ea44ac9c1553e888ebc70ff1e4daa4625b |
| turbo-cache-control | no-preview |
| go-import | github.com/grandyang/leetcode git https://github.com/grandyang/leetcode.git |
| octolytics-dimension-user_id | 8553010 |
| octolytics-dimension-user_login | grandyang |
| octolytics-dimension-repository_id | 189444423 |
| octolytics-dimension-repository_nwo | grandyang/leetcode |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 189444423 |
| octolytics-dimension-repository_network_root_nwo | grandyang/leetcode |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 309153364422b3c499922d1a2a6404910a58ed8e |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width