英文:
Flatten Binary Tree to Linked List (Java)_ why this recursive code not working?
问题
Leetcode问题如下:
描述
以前序遍历将二叉树展开为一颗伪“链表”。
在这里,我们使用TreeNode中的右指针作为ListNode中的下一个指针。
输入:{1,2,5,3,4,#,6}
输出:{1,#,2,#,3,#,4,#,5,#,6}
解释:
1
/ \
2 5
/ \ \
3 4 6
1
\
2
\
3
\
4
\
5
\
6
下面的代码不能返回预期结果,但是无法弄清楚原因:
public class Solution {
public void flatten (TreeNode root){
TreeNode lastNode = null;
helper (root, lastNode);
}
private void helper(TreeNode root, TreeNode lastNode){
if (root == null){
return;
}
if(lastNode != null){
lastNode.left = null;
lastNode.right = root;
}
lastNode = root;
TreeNode right = root.right;
helper(root.left, lastNode);
helper(right, lastNode);
}
}
测试结果:
输入
{1,2,5,3,4,#,6}
输出
{1,#,5,#,6}
预期结果
{1,#,2,#,3,#,4,#,5,#,6}
不理解为什么输出是{1,#,5,#,6},而不是预期的{1,#,2,#,3,#,4,#,5,#,6}。有人能解释一下吗?谢谢
英文:
Leetcode question as below:
Description
Flatten a binary tree to a fake "linked list" in pre-order traversal.
Here we use the right pointer in TreeNode as the next pointer in ListNode.
Input:{1,2,5,3,4,#,6}
Output:{1,#,2,#,3,#,4,#,5,#,6}
Explanation:
1
/ \
2 5
/ \ \
3 4 6
1
\
2
\
3
\
4
\
5
\
6
code below does not return expected, but could not figure out why:
public class Solution {
public void flatten (TreeNode root){
TreeNode lastNode = null;
helper (root, lastNode);
}
private void helper(TreeNode root, TreeNode lastNode){
if (root == null){
return;
}
if(lastNode != null){
lastNode.left = null;
lastNode.right = root;
}
lastNode = root;
TreeNode right = root.right;
helper(root.left, lastNode);
helper(right, lastNode);
}
}
test result:
Input
{1,2,5,3,4,#,6}
Output
{1,#,5,#,6}
Expected
{1,#,2,#,3,#,4,#,5,#,6}
Couldn't understand why the output will be {1,#,5,#,6} instead of expected of {1,#,2,#,3,#,4,#,5,#,6}. Can anyone explain?Thanks
答案1
得分: 2
你的代码基本写得很好,但存在一个小错误。在编写代码时,你假设 lastNode
在进行先序遍历时会更新为最后一个节点。但事实并非如此。
在递归调用返回到这行代码 helper(right, lastNode);
后,lastNode
变量仍然指向当前最后一个节点。
让我们举个例子。假设我们在节点 2,所以我们将 lastNode
更改为节点 2,然后调用它的左子节点。在执行 helper(root.left, lastNode);
这行代码之后,我们认为 lastNode
应该指向节点 3。但事实并非如此,它仍然指向节点 2。
让我们看看调试器对上述情景的输出:
为了消除这个错误,我们应该在递归调用期间返回 lastNode
。
请参考下面的示例代码:
private TreeNode helper(TreeNode root, TreeNode lastNode){
if (root == null){
return lastNode;
}
if(lastNode != null){
lastNode.left = null;
lastNode.right = root;
}
lastNode = root;
TreeNode right = root.right;
lastNode = helper(root.left, lastNode);
lastNode = helper(right, lastNode);
return lastNode;
}
经过上述更改,结果将会是这样的:
英文:
You have almost coded it well, but there's a small bug. While writing the code you are assuming that the lastNode
is updated to the last node while visiting in pre-order. But that is not the case.
The lastNode
variable is still pointing to the current last node, after the recursion call is back at this line helper(right, lastNode);
.
Let us take an example. Suppose we are at node 2, so we change the lastNode
to node 2 and then call its left child. After the helper(root.left, lastNode);
line is executed, we believe that lastNode
should point to node 3. But that is not the case, it's still pointing to node 2.
Let's see what the debugger says for the above scenario
What should we do to remove this bug, Just return the lastNode during the recursion call.
See the example code below
private TreeNode helper(TreeNode root, TreeNode lastNode){
if (root == null){
return lastNode;
}
if(lastNode != null){
lastNode.left = null;
lastNode.right = root;
}
lastNode = root;
TreeNode right = root.right;
lastNode = helper(root.left, lastNode);
lastNode = helper(right, lastNode);
return lastNode;
}
After the above changes, the result is something like this
答案2
得分: 1
private void helper(TreeNode root, TreeNode lastNode){
if (root == null){
return;
}
if(lastNode != null){
lastNode.left = null; // *** 1
lastNode.right = root; // *** 1
}
lastNode = root;
TreeNode right = root.right;
helper(root.left, lastNode); // *** 2
helper(right, lastNode); // *** 3
}
在第一部分,你将左子节点连接到该lastNode的右侧。
在第二部分,你调用左子节点,在此期间将执行第一部分。
在第三部分,你调用右子节点,在此期间将执行第一部分。
因此,当第二部分完成其工作时,通过调用第一部分,lastNode将已经具有右子节点。当调用第三部分并执行其自己的代码的第一部分时,它将覆盖第二部分中完成的工作。
你可能想要做的是在helper函数中返回"叶子",并将叶子用作lastNode(即节点4,而不是根节点)。
private TreeNode helper(TreeNode root, TreeNode leaf){
if (root != null){
if (leaf != null){
leaf.left = null; // *** 1
leaf.right = root; // *** 1
}
leaf = root;
TreeNode right = root.right;
leaf = helper(root.left, leaf); // *** 2
leaf = helper(right, leaf); // *** 3
}
return leaf;
}
英文:
private void helper(TreeNode root, TreeNode lastNode){
if (root == null){
return;
}
if(lastNode != null){
lastNode.left = null; // *** 1
lastNode.right = root; // *** 1
}
lastNode = root;
TreeNode right = root.right;
helper(root.left, lastNode); // *** 2
helper(right, lastNode); // *** 3
}
In section 1, you attach the left children to the right for this lastNode.
In section 2, you call for the left children, where section 1 will be executed.
In section 3, you call for the right children, where section 1 will be executed.
So when section 2 completes it's work, lastNode will have right children already by calling section 1. When section 3 is called and it performs its own section 1 of the code, it will overwrite the work done in section 2.
What you probably want to do is return the "leaf" in the helper function and use the leaf as the lastNode (i.e. Node 4, instead of root).
private TreeNode helper(TreeNode root, TreeNode leaf){
if (root != null){
if (leaf != null){
leaf.left = null; // *** 1
leaf.right = root; // *** 1
}
leaf = root;
TreeNode right = root.right;
leaf = helper(root.left, leaf); // *** 2
leaf = helper(right, leaf); // *** 3
}
return leaf;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论