好友抖音面試真題:297.二叉樹的序列化與反序列化

好友抖音面試

前段時間,好朋友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】原創文章,未經容許,謝絕轉載!

相關文章
相關標籤/搜索