2020.8.2 力扣每日

1 class Solution { 2 public void flatten(TreeNode root) { 3 if (root == null) { 4 return; 5 } 6 Deque<TreeNode> stack = new LinkedList<TreeNode>(); 7 stack.push(root); 8 TreeNode prev = null; 9 while (!stack.isEmpty()) { 10 TreeNode curr = stack.pop(); 11 if (prev != null) { 12 prev.left = null; 13 prev.right = curr; 14 } 15 TreeNode left = curr.left, right = curr.right; 16 if (right != null) { 17 stack.push(right); 18 } 19 if (left != null) { 20 stack.push(left); 21 } 22 prev = curr; 23 } 24 } 25 }
解题思路:
根据题目中的样例分析,可以发现,其单链表的顺序是二叉树前序遍历的结果。所以该题需要使用二叉树的前序遍历,一般的前序遍历可以使用递归或栈的方式来解决。由于此题中最终形成的单链表实际上是一棵左子树为空的二叉树,如果使用递归,那么就需要临时存储下递归结果。最后再遍历结果生成二叉树,效率上并不高。所以此处采用栈来进行处理,通过取出栈顶元素,将节点的左右节点依次压入栈内,重复该操作,就能实现二叉树的先序遍历。
在遍历的同时,也只需要将取出的栈顶元素,连接至上一个取出元素的右节点即可。
注意:
- 由于栈是先进后出,而我们需要遍历的顺序时父节点,左节点,右节点,所以左节点需比右节点先出栈,即入栈顺序为右节点先入栈,左节点再入栈。
- 由于最后生成的链表为特殊二叉树,在结果处理上,我们需要将节点的左节点置null,否则最后生成的结果与预期不符。
时间复杂度:O(N),N为二叉树节点数。
空间复杂度:O(N)
优化:
这样的解决方案,仍然可以进行优化。我们可以根据前序遍历发现,所有根节点的右节点的节点访问顺序,都是在根节点的左子树访问的最后一个节点后,也就是说我们可以提前将根节点的右节点移动到左子树最后访问的一个节点的右子树,这样的话,所有节点的访问顺序仍和移动前一样,我们可以对每次访问的左节点都做此操作,那么我们就不需要使用栈来记录右节点,所以我们可以将空间复杂度缩减到O(1),也就是说,我们只需要判断每个节点的左节点状态,非空,遍历左节点。为空,遍历右节点即可。
1 class Solution { 2 public void flatten(TreeNode root) { 3 TreeNode curr = root; 4 while (curr != null) { 5 if (curr.left != null) { 6 TreeNode next = curr.left; 7 TreeNode predecessor = next; 8 while (predecessor.right != null) { //寻找左子树的前序遍历最后一个节点 9 predecessor = predecessor.right; 10 } 11 predecessor.right = curr.right; //移动当前右子树 12 curr.left = null; //创建,连接二叉树形成单链表 13 curr.right = next; 14 } 15 curr = curr.right; //左子数为空,遍历右子树 16 } 17 } 18 }
时间复杂度:O(N)
空间复杂度:O(1)

浙公网安备 33010602011771号