📢 preface
- 🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻
- 🌲 Punching out an algorithm problem every day is not only a learning process, but also a sharing process 😜
- 🌲 Tip: the problem-solving programming languages in this column are C# and Java
- 🌲 To maintain a state of learning every day, let's work together to become the great God of algorithm 🧐!
- 🌲 Today is the 40th day of punching out the force deduction algorithm 🎈!
- 🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻🌻
🌲 Example of the original problem: post order traversal of binary tree
Given a binary tree, return its postorder traversal.
Example 1:
input: [1,null,2,3] 1 \ 2 / 3 output: [3,2,1]
🌻 C# method 1: iteration
Only one stack is used to complete the subsequent traversal. The steps are as follows:
- Always access to the left node;
- Press the nodes into the stack in the order of root node - > right node - > left node;
- When the leaf node is touched, it starts to exit the stack;
- If the node pointed to by the current stack top element still has unreachable child nodes, return to step 1 and cycle back and forth;
- If the stack is empty, the traversal ends.
The difficulty lies in how to judge whether the top node of the stack has unreachable child nodes.
If the judgment method is improper, it is likely that the top node of the stack is the parent node of the last out of the stack node, resulting in its nodes repeatedly entering the stack and falling into an endless loop.
You can add a variable or pointer to the previous node that has been out of the stack.
Each time you judge the top node of the stack, you only need to judge in advance whether it is a parent-child relationship with the last out of the stack node. If so, continue to out of the stack, otherwise go back to step 1 above and start the stack entry cycle.
public class Solution { public IList<int> PostorderTraversal(TreeNode root) { List<int> rst = new List<int>(); if(root == null) return rst; Stack<TreeNode> st = new Stack<TreeNode>(); TreeNode node = root; TreeNode printNode = root; TreeNode tmp = null; st.Push(node); while(st.Any()) { tmp = null; if(node.left != printNode && node.right != printNode) { if(node.right != null) { st.Push(node.right); tmp = node.right; } if(node.left != null) { st.Push(node.left); tmp = node.left; } } node = tmp; if(tmp == null) { rst.Add((printNode = st.Pop()).val); if(st.Any()) node = st.Peek(); } } return rst; } }
results of enforcement
The execution passed, the execution time was 284ms, and the memory consumption was 30.1MB
🌻 Java method 1: recursion
Ideas and algorithms
First of all, we need to know what is the post order traversal of a binary tree: we traverse the tree by accessing the left subtree - right subtree - root node, and when accessing the left subtree or right subtree, we traverse in the same way until we traverse the whole tree.
Therefore, the whole traversal process has the nature of recursion. We can directly simulate this process with recursive functions.
Define a postmaster (root) to represent the answer to the current traversal to the root node.
By definition, we only need to recursively call postmaster (root - > left) to traverse the left subtree of the root node, then recursively call postmaster (root - > right) to traverse the right subtree of the root node, and finally add the value of the root node to the answer. The condition for recursive termination is to encounter an empty node.
class Solution { public List<Integer> postorderTraversal(TreeNode root) { List<Integer> res = new ArrayList<Integer>(); postorder(root, res); return res; } public void postorder(TreeNode root, List<Integer> res) { if (root == null) { return; } postorder(root.left, res); postorder(root.right, res); res.add(root.val); } }
results of enforcement
Implementation passed
Execution time 0 ms, At all Java Defeated 100 in submission.00%User Memory consumption 36.6 MB, At all Java Defeated 68 in submission.49%User
🌻 Java method 2: iteration
General idea
We can also implement the recursive function of method 1 in an iterative way. The two methods are equivalent. The difference is that a stack is implicitly maintained during recursion,
When iterating, we need to explicitly simulate the stack. The rest of the implementation and details are the same. For details, please refer to the following code.
class Solution { public List<Integer> postorderTraversal(TreeNode root) { List<Integer> res = new ArrayList<Integer>(); if (root == null) { return res; } Deque<TreeNode> stack = new LinkedList<TreeNode>(); TreeNode prev = null; while (root != null || !stack.isEmpty()) { while (root != null) { stack.push(root); root = root.left; } root = stack.pop(); if (root.right == null || root.right == prev) { res.add(root.val); prev = root; root = null; } else { stack.push(root); root = root.right; } } return res; } }
results of enforcement
results of enforcement
Implementation passed
Execution time 0 ms, At all Java Defeated 100 in submission.00%User Memory consumption 36.7 MB, At all Java Defeated 40 in submission.52%User
💬 summary
- Today is the fortieth day of punching out the force deduction algorithm!
- This paper uses C# and Java programming languages to solve problems
- Some methods are also written by Likou God, and they are also shared while learning. Thanks again to the algorithm bosses
- That's the end of today's algorithm sharing. See you tomorrow!