題目地址:
https://leetcode.com/problems/find-leaves-of-binary-tree/
給定一棵二叉樹,每次蒐集其葉子的值,並把葉子刪掉,再重複這樣的操作直到整棵樹都變空爲止。
法1:多次遞歸,每次蒐集並且刪掉葉子的方法就是,如果走到了葉子,就將葉子加入列表,並返回null
給上一層,連到進入這一層遞歸時的父親節點上。如此這樣直到整棵樹被刪乾淨爲止。代碼如下:
import java.util.ArrayList;
import java.util.List;
public class Solution {
public List<List<Integer>> findLeaves(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
// 只有樹不空,就蒐集並刪除葉子,並將葉子加入res
while (root != null) {
List<Integer> leaves = new ArrayList<>();
root = dfs(root, leaves);
res.add(leaves);
}
return res;
}
// 返回刪掉root子樹葉子後的樹根
private TreeNode dfs(TreeNode root, List<Integer> cur) {
if (root == null) {
return null;
}
// 遇到葉子,則加入cur列表中,並返回null,也就是將葉子刪掉
if (root.left == null && root.right == null) {
cur.add(root.val);
return null;
}
// 將左右子樹葉子刪掉後返回刪掉葉子後的左右樹根,並連到原樹根上去
root.left = dfs(root.left, cur);
root.right = dfs(root.right, cur);
return root;
}
}
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int x) {
val = x;
}
}
時間複雜度,空間。
對於滿二叉樹而言,時間複雜度由給出。最差的情況是二叉樹退化成鏈表,則需要的時間。
法2:我們考慮每個節點應該要加到res的哪一層裏,容易發現,一個節點應該加在res的哪個位置與其到其左右子樹最深的葉子有多少步有關(稱爲這個節點的高度)。所以我們可以在遞歸回溯的時候算得這個節點的深度,然後按照深度加到res的對應位置的列表上。這樣就避免了法1裏的頻繁DFS導致節點被重複搜索的問題(實際上就是後序遍歷)。代碼如下:
import java.util.ArrayList;
import java.util.List;
public class Solution {
public List<List<Integer>> findLeaves(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
dfs(root, res);
return res;
}
private int dfs(TreeNode root, List<List<Integer>> res) {
// 葉子的高度是0,所以規定走到null就返回-1
if (root == null) {
return -1;
}
// 得到root的高度
int height = 1 + Math.max(dfs(root.left, res), dfs(root.right, res));
// 如果這個高度對應的位置沒有list,就new一個出來,並把root的值加進去
if (height >= res.size()) {
res.add(new ArrayList<>());
}
res.get(height).add(root.val);
return height;
}
}
時間複雜度,空間。