「这是我参与2022首次更文挑战的第35天,活动详情查看:2022首次更文挑战」。
题目:给定二叉树的根节点root,要求将此二叉树展开为一个链表,链表要求如下:
- 二叉树展开后的链表结构应该同样使用原始
TreeNode数据结构,并且其左指针指向空,右指针指向链表的下一个节点。 - 二叉树展开后的链表应该和二叉树的先序遍历保持相同顺序。
解题思路
本题要求最终的链表顺序和二叉树的先序遍历保持相同,那么可以将二叉树先得到先序遍历的结果,之后修改结果集合中的每个节点的指针指向即可,获得先序遍历的方式有递归法和非递归法,递归法较为简单,可得如下代码:
public void flatten(TreeNode root) {
if(root==null) return;
ArrayList<TreeNode> temp = new ArrayList<>();
preOrder(root, temp);
for(int i=1;i<temp.size();i++){
TreeNode pre = temp.get(i-1), curr=temp.get(i);
pre.left = null;
pre.right=curr;
}
}
public void preOrder(TreeNode root, ArrayList<TreeNode> temp){
if(root==null) return;
temp.add(root);
if(root.left!=null) preOrder(root.left, temp);
if(root.right!=null) preOrder(root.right, temp);
}
上述代码时间复杂度和空间复杂度都为。非递归法和之前先序遍历一样,都需要使用栈数据结构,此处使用的是Java中的 双端队列ArrayDeque 作为栈,可得如下代码:
public void flatten(TreeNode root) {
if(root==null) return;
TreeNode cur = root;
ArrayDeque<TreeNode> deque = new ArrayDeque<>();
ArrayList<TreeNode> list = new ArrayList<>();
deque.push(cur);
while (!deque.isEmpty()){
cur = deque.pop();
list.add(cur);
if(cur.right!=null){
deque.push(cur.right);
}
if(cur.left!=null){
deque.push(cur.left);
}
}
for(int i=1;i<list.size();i++){
TreeNode pre = list.get(i-1), curr=list.get(i);
pre.left = null;
pre.right=curr;
}
}
上述代码中最后一个for循环中的i值为0时,就代表的是root节点,因此最终结果属于原地修改。但代码的时间复杂度和空间复杂度仍为。而题中要求使用空间复杂度来展开,如何解决呢?参考评论区一位大佬的题解,虽然我写不出来~ 代码如下:
TreeNode last = null;
public void flatten(TreeNode root) {
if(root==null) return;
flatten(root.right);
flatten(root.left);
root.right=last;
root.left=null;
last=root;
}
代码相对于官方题解容易理解的多,最终耗时为0ms,空间复杂度为。