前段時間,好朋友Hellovass參加抖音的面試(高級Android開發工程師)。按照字節的慣例,手擼算法是跑不了的。首先在這裏祝好朋友在抖音一切順利,事事順心。java
終於有心思靜下心來搞點事情了,第一件事就是先回顧下好友的面試真題:LeetCode第297題——《二叉樹的序列化與反序列化》。node
這是一道難度爲Hard的題目,其實若是熟悉二叉樹的BFS和DFS的話,思路應該會是比較水到渠成的。面試
回到這個題目,題意是你怎麼把二叉樹變成"一串字符串",而後又怎麼經過字符串重組回一顆二叉樹。首先要序列化一顆二叉樹,首先確定要遍歷樹的各個節點吧:有DFS(深度優先遍歷)和BFS(廣度優先遍歷)。這個題我最開始的想法就是BFS,由於遞歸是比較抽象的(本人水平有限,因此就抽象了),因此我不會第一時間就往遞歸上面去想。算法
假設一棵樹:markdown
2
/ \
1 3
複製代碼
BFS的結果是:app
2,1,3
複製代碼
由 2,1,3 怎麼重建二叉樹呢,不難發現,咱們先把根節點2拿出去,剩下的1和3就分別是2的左右孩子了。學習
假設這棵樹再大一點:(題目那顆)ui
1
/ \
2 3
/ \
4 5
複製代碼
BFS的結果是:spa
1,2,3,4,5
複製代碼
根據上面的思想,先把root節點拿出來,取後面的兩個分別做爲左右孩子:code
1
/ \
2 3
複製代碼
這裏沒問題,繼續爲2找左右孩子,這時候就取到4,5了,變成:
1
/ \
2 3
/ \
4 5
複製代碼
這裏顯然就不對了。其實題目已經給了tips:
用上面的思想,按照:
1,2,3,null,null,4,5
複製代碼
來重建二叉樹,就沒有問題了。
那麼思路就很清晰了,思路清晰也不表明代碼好寫,這是兩碼事;寫完代碼也不見得全部的test case都能pass。
先把序列化的寫了,比較傳統的BFS,碰到左右子樹爲空的則輸出爲nil字符串,這裏任意能區分的字符便可。
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
if (root == null) {
return "nil";
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
StringBuilder sb = new StringBuilder();
while (!queue.isEmpty()) {
TreeNode poll = queue.remove();
if (poll == null) {
sb.append("nil").append(",");
continue;
}
sb.append(poll.val).append(",");
queue.add(poll.left);
queue.add(poll.right);
}
return sb.substring(0, sb.length() - 1);
}
複製代碼
反序列化的代碼,也是要用到一個隊列,跟遍歷同樣,先把root節點放到隊列中,而後不斷地循環,把須要找左右孩子的節點繼續放入到隊列中去:(經過代碼註釋來說解)
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
if (data == null || data.isBlank()) {
return null;
}
String[] split = data.split(",");
// 這裏不要忘記了判斷第一個結果就是空的狀況,本人在這裏提交了幾遍才找出問題
if ("nil".equals(split[0])) {
return null;
}
// 先把root節點放到queue裏面去
TreeNode root = new TreeNode(Integer.parseInt(split[0]));
// index就是你要開始找的孩子節點的位置了。
// 第2、三個節點確定是root節點的左右孩子;
// 而後以此類推:4、五 節點必定是二號節點的左右孩子
int index = 1;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
// 從隊列裏拿出一個節點,而後找它的左右孩子
TreeNode node = queue.remove();
// 左孩子就是當前index的位置
String v1 = split[index++];
// 左孩子
if (!"nil".equals(v1)) {
node.left = new TreeNode(Integer.parseInt(v1));
queue.add(node.left);
}
// 右孩子
String v2 = split[index++];
if (!"nil".equals(v2)) {
node.right = new TreeNode(Integer.parseInt(v2));
queue.add(node.right);
}
}
return root;
}
複製代碼
寫完放到LeetCode上跑一下看看:
擊敗數並不高,說明還有更好的寫法。可是若是你是面試,其實到這裏就已經沒有問題了。固然學習不全是爲了面試,要否則就真的太累了,但願你們都能找到個好公司,節日福利多多的那種。
【Happyjava】原創文章,未經容許,謝絕轉載!