1. 程式人生 > 其它 >leetcode 652. Find Duplicate Subtrees(找出重複的子樹)

leetcode 652. Find Duplicate Subtrees(找出重複的子樹)

技術標籤:leetcodeleetcode演算法

Given the root of a binary tree, return all duplicate subtrees.

For each kind of duplicate subtrees, you only need to return the root node of any one of them.

Two trees are duplicate if they have the same structure with the same node values.

Example 1:
在這裡插入圖片描述
Input: root = [1,2,3,4,null,2,4,null,null,4]

Output: [[2,4],[4]]

給出一個二叉樹,找出其中相同的子樹,相同的子樹是指相同的節點值,相同的結構,多個重複的只需返回一個,返回root節點即可。

思路:
如果遍歷到每一個節點都可以返回這個節點下面的樹結構和值的組合(具有唯一性),即可以迅速判斷是不是同一棵子樹。序列化有這個唯一性,可以用序列化解決。
但是看到網上有個更快的方法,類似序列化。它是用long型儲存一棵二叉樹,其中高位32位到16位儲存root,中間16位儲存左子樹,下面16位儲存右子樹,這樣每個樹可形成一個long型的key。
root可直接儲存值,但是左右子樹需要一個int型的id來儲存,因為只儲存值的話區分不出結構。所以每個key又對應一個id,id對應這一結構子樹的count。

所以需要兩個hashMap,一個儲存<key, id>, 一個儲存<id, count>
root的id是0,[2,4]的id是1,[4]的id是2,當出現下一個[2,4]時,通過計算key找到相同的id是1,再通過id找到count,一旦count == 2,說明之前出現過一次,儲存進結果即可,count>2的就不需要再儲存了。

為什麼不直接通過key找count,因為key中需要id來儲存左右子樹,只用key的話超出long型範圍。
同時注意root的值儲存進key時必須要cast到long型,因為它要左移32位,如果直接用int,會溢位。
另外count要先+1再判斷是否 == 2. 而不是直接判斷是不是 == 1,因為有些出現過1次但是和本次的key並不相同的也會算進去。

//6ms
    public List<TreeNode> findDuplicateSubtrees(TreeNode root) {
        List<TreeNode> result = new ArrayList<>();
        if(root == null) return result;
        
        HashMap<Long, Integer> ids = new HashMap<>();
        HashMap<Integer, Integer> count = new HashMap();
        getId(root, ids, count, result);
        
        return result;
    }
    
    int getId(TreeNode root, HashMap<Long, Integer> ids,
             HashMap<Integer,Integer> count, List<TreeNode> result) {
        if(root == null) return 0;
        
        long key = ((long)root.val << 32 | getId(root.left, ids, count, result) << 16 |
            getId(root.right, ids, count, result));
        int id = 0;
        
        if(ids.get(key) != null) {
            id = ids.get(key);
        } else {
            id = ids.size() + 1;
        }
        
        ids.put(key, id);
        count.put(id, count.getOrDefault(id, 0)+1);
        if(count.get(id) == 2) {
            result.add(root);
        }
        
        return id;
    }

參考資料