package tree; import java.util.ArrayList; import java.util.Deque; import java.util.LinkedList; import java.util.List; /** * 题目: 114. 二叉树展开为链表 (rightSideView) * 描述:给你二叉树的根结点 root ,请你将它展开为一个单链表: * 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。 * 展开后的单链表应该与二叉树 先序遍历 顺序相同。 进阶:你可以使用原地算法(O(1) 额外空间)展开这棵树吗? * 链接:https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/ */ //二刷会普通方法 不会空间O1的 //todo:学习一下思路。 public class Flatten { public void inOrderTraversal(TreeNode root,Listlist){ if(root!=null) { list.add(root); inOrderTraversal(root.left, list); inOrderTraversal(root.right, list); } } //O(N)空间复杂度 递归前序 public void flatten2(TreeNode root) { Listlist=new ArrayList<>(); TreeNode tp= new TreeNode(0); inOrderTraversal(root,list); for (TreeNode treeNode : list) { tp.left=null; tp.right=treeNode; tp=tp.right; } } //迭代前序遍历也要会! public void flatten1(TreeNode root) { if (root == null) { return; } Deque stack = new LinkedList<>(); stack.push(root); TreeNode prev = null; while (!stack.isEmpty()) { TreeNode curr = stack.pop(); if (prev != null) { prev.left = null; prev.right = curr; } TreeNode left = curr.left, right = curr.right; if (right != null) { stack.push(right); } if (left != null) { stack.push(left); } prev = curr; } } //O(1)空间 很妙 /** * 原地展开二叉树为单链表(先序顺序) * 思路:Morris 遍历的变形 —— 每到一个有左子树的节点,就把 * ① 左子树插到右边 * ② 左子树最右节点 (predecessor) 的 right 指针接到原来的右子树 * ③ 左指针置空 * 然后继续沿着 curr = curr.right 前进 * 时间复杂度:O(n) — 每条边最多访问两次 * 空间复杂度:O(1) — 仅用常数指针 * https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/solutions/356853/er-cha-shu-zhan-kai-wei-lian-biao-by-leetcode-solu/?envType=study-plan-v2&envId=top-100-liked */ public void flatten(TreeNode root) { TreeNode curr = root; // 当前遍历到的节点 while (curr != null) { if (curr.left != null) { // 只处理存在左子树的节点 TreeNode next = curr.left; // 1) 记录左子树的根,稍后会挪到右边 // 2) 找到左子树中的最右节点(先序遍历的“前驱”) TreeNode predecessor = next; while (predecessor.right != null) { predecessor = predecessor.right; } // 3) 把当前节点原本的右子树接到 predecessor 的右侧 predecessor.right = curr.right; // 4) 把左子树搬到右边,左指针清空 curr.left = null; curr.right = next; } // 5) 向“链表”右侧移动,继续处理下一个节点 curr = curr.right; } } }