[Leetcode][第114题][JAVA][二叉树展开为链表][递归][迭代]
【問(wèn)題描述】[中等]
【解答思路】
1. 前序遍歷
將二叉樹展開為單鏈表之后,單鏈表中的節(jié)點(diǎn)順序即為二叉樹的前序遍歷訪問(wèn)各節(jié)點(diǎn)的順序。因此,可以對(duì)二叉樹進(jìn)行前序遍歷,獲得各節(jié)點(diǎn)被訪問(wèn)到的順序。
由于將二叉樹展開為鏈表之后會(huì)破壞二叉樹的結(jié)構(gòu),因此在前序遍歷結(jié)束之后更新每個(gè)節(jié)點(diǎn)的左右子節(jié)點(diǎn)的信息,將二叉樹展開為單鏈表。
時(shí)間復(fù)雜度:O(N) 空間復(fù)雜度:O(N)
遞歸(自上而下)
class Solution {public void flatten(TreeNode root) {List<TreeNode> list = new ArrayList<TreeNode>();preorderTraversal(root, list);int size = list.size();for (int i = 1; i < size; i++) {TreeNode prev = list.get(i - 1), curr = list.get(i);prev.left = null;prev.right = curr;}}public void preorderTraversal(TreeNode root, List<TreeNode> list) {if (root != null) {list.add(root);preorderTraversal(root.left, list);preorderTraversal(root.right, list);}} }迭代
時(shí)間復(fù)雜度:O(N) 空間復(fù)雜度:O(N)
2. 前序遍歷和展開同時(shí)進(jìn)行
時(shí)間復(fù)雜度:O(N) 空間復(fù)雜度:O(N)
3. 前驅(qū)節(jié)點(diǎn)
前兩種方法都借助前序遍歷,前序遍歷過(guò)程中需要使用棧存儲(chǔ)節(jié)點(diǎn)。有沒(méi)有空間復(fù)雜度是 O(1)O(1) 的做法呢?
注意到前序遍歷訪問(wèn)各節(jié)點(diǎn)的順序是根節(jié)點(diǎn)、左子樹、右子樹。如果一個(gè)節(jié)點(diǎn)的左子節(jié)點(diǎn)為空,則該節(jié)點(diǎn)不需要進(jìn)行展開操作。如果一個(gè)節(jié)點(diǎn)的左子節(jié)點(diǎn)不為空,則該節(jié)點(diǎn)的左子樹中的最后一個(gè)節(jié)點(diǎn)被訪問(wèn)之后,該節(jié)點(diǎn)的右子節(jié)點(diǎn)被訪問(wèn)。該節(jié)點(diǎn)的左子樹中最后一個(gè)被訪問(wèn)的節(jié)點(diǎn)是左子樹中的最右邊的節(jié)點(diǎn),也是該節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)。因此,問(wèn)題轉(zhuǎn)化成尋找當(dāng)前節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)。
步驟
對(duì)于當(dāng)前節(jié)點(diǎn),如果其左子節(jié)點(diǎn)不為空,則在其左子樹中找到最右邊的節(jié)點(diǎn),作為前驅(qū)節(jié)點(diǎn),將當(dāng)前節(jié)點(diǎn)的右子節(jié)點(diǎn)賦給前驅(qū)節(jié)點(diǎn)的右子節(jié)點(diǎn),然后將當(dāng)前節(jié)點(diǎn)的左子節(jié)點(diǎn)賦給當(dāng)前節(jié)點(diǎn)的右子節(jié)點(diǎn),并將當(dāng)前節(jié)點(diǎn)的左子節(jié)點(diǎn)設(shè)為空。對(duì)當(dāng)前節(jié)點(diǎn)處理結(jié)束后,繼續(xù)處理鏈表中的下一個(gè)節(jié)點(diǎn),直到所有節(jié)點(diǎn)都處理結(jié)束。
時(shí)間復(fù)雜度:O(N) 空間復(fù)雜度:O(1)
遞歸寫法
1/ \2 5/ \ \ 3 4 6//將 1 的左子樹插入到右子樹的地方1\2 5/ \ \3 4 6 //將原來(lái)的右子樹接到左子樹的最右邊節(jié)點(diǎn)1\2 / \ 3 4 \5\6//將 2 的左子樹插入到右子樹的地方1\2 \ 3 4 \5\6 //將原來(lái)的右子樹接到左子樹的最右邊節(jié)點(diǎn)1\2 \ 3 \4 \5\6遞歸版本
相應(yīng)的左孩子也要置為 null,同樣的也不用擔(dān)心左孩子丟失,因?yàn)槭呛笮虮闅v,左孩子已經(jīng)遍歷過(guò)了
private TreeNode pre = null;public void flatten(TreeNode root) {if (root == null)return;flatten(root.right);flatten(root.left);root.right = pre;root.left = null;pre = root; }【總結(jié)】
1. 解法一二 自頂向下 解法三 自底向上
2.List接口常用方法
// 1、將指定的元素,添加到該集合中的指定位置上。 public void add(int index, E element)// 2、返回集合中指定位置的元素。 public E get(int index)// 3、移除列表中指定位置的元素,返回的是被移除的元素。 public E remove(int index)// 4、用指定元素替換集合中指定位置的元素,返回值的更新前的元素。 public E set(int index, E element)3.遞歸
在實(shí)現(xiàn)遞歸函數(shù)之前,有兩件重要的事情需要弄清楚:
遞推關(guān)系:一個(gè)問(wèn)題的結(jié)果與其子問(wèn)題的結(jié)果之間的關(guān)系。
基本情況:不需要進(jìn)一步的遞歸調(diào)用就可以直接計(jì)算答案的情況。可理解為遞歸跳出條件。
一旦我們計(jì)算出以上兩個(gè)元素,再想要實(shí)現(xiàn)一個(gè)遞歸函數(shù),就只需要根據(jù)遞推關(guān)系調(diào)用函數(shù)本身,直到其抵達(dá)基本情況。
轉(zhuǎn)載鏈接:https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/solution/er-cha-shu-zhan-kai-wei-lian-biao-by-leetcode-solu/
參考鏈接:https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by–26/
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的[Leetcode][第114题][JAVA][二叉树展开为链表][递归][迭代]的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 单目标跟踪MOSSE详细算法步骤+理论说
- 下一篇: 第二课 决策树与随机森林