Welcome to Subscribe On Youtube

508. Most Frequent Subtree Sum

Description

Given the root of a binary tree, return the most frequent subtree sum. If there is a tie, return all the values with the highest frequency in any order.

The subtree sum of a node is defined as the sum of all the node values formed by the subtree rooted at that node (including the node itself).

 

Example 1:

Input: root = [5,2,-3]
Output: [2,-3,4]

Example 2:

Input: root = [5,2,-5]
Output: [2]

 

Constraints:

  • The number of nodes in the tree is in the range [1, 104].
  • -105 <= Node.val <= 105

Solutions

Solution 2: Hash Table + Explicit Stack

Thinking

A subtree sum is the left sum plus the right sum plus the node value, so both children must be known first. Rescanning each subtree repeats work. Returning the sum from a postorder recursion is correct on a short tree.

The tree can contain $10^4$ nodes. A left chain makes this postorder walk recurse once per node and overflow the call stack.

Each sum depends only on the two children, so children must be finished before their parent. Frequencies can be counted in a hash table during the walk.

An explicit stack performs that postorder walk. On entry it pushes an exit marker and the two children; on exit it writes the subtree sum into the hash table. After the walk, the sums with the highest frequency are the answer.

A hash table $\textit{cnt}$ records how often each subtree sum appears. An explicit stack walks the binary tree in postorder. On entry we push an exit marker, then the right child and the left child. On exit the children’s sums are already stored, the current sum is those two plus the node value, and $\textit{cnt}$ is updated.

Finally we keep every subtree sum whose frequency is maximal.

The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree.

  • /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode() {}
     *     TreeNode(int val) { this.val = val; }
     *     TreeNode(int val, TreeNode left, TreeNode right) {
     *         this.val = val;
     *         this.left = left;
     *         this.right = right;
     *     }
     * }
     */
    class Solution {
        private Map<Integer, Integer> counter;
        private int mx;
    
        public int[] findFrequentTreeSum(TreeNode root) {
            counter = new HashMap<>();
            mx = Integer.MIN_VALUE;
            dfs(root);
            List<Integer> res = new ArrayList<>();
            for (Map.Entry<Integer, Integer> entry : counter.entrySet()) {
                if (entry.getValue() == mx) {
                    res.add(entry.getKey());
                }
            }
            int[] ans = new int[res.size()];
            for (int i = 0; i < res.size(); ++i) {
                ans[i] = res.get(i);
            }
            return ans;
        }
    
        private int dfs(TreeNode root) {
            if (root == null) {
                return 0;
            }
            int s = root.val + dfs(root.left) + dfs(root.right);
            counter.put(s, counter.getOrDefault(s, 0) + 1);
            mx = Math.max(mx, counter.get(s));
            return s;
        }
    }
    
    
    // Solution 2
    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode() {}
     *     TreeNode(int val) { this.val = val; }
     *     TreeNode(int val, TreeNode left, TreeNode right) {
     *         this.val = val;
     *         this.left = left;
     *         this.right = right;
     *     }
     * }
     */
    class Solution {
        private static class Frame {
            TreeNode node;
            int state;
    
            Frame(TreeNode node, int state) {
                this.node = node;
                this.state = state;
            }
        }
    
        public int[] findFrequentTreeSum(TreeNode root) {
            Map<Integer, Integer> cnt = new HashMap<>();
            Map<TreeNode, Integer> sub = new IdentityHashMap<>();
            int mx = 0;
            if (root != null) {
                Deque<Frame> stk = new ArrayDeque<>();
                stk.push(new Frame(root, 0));
                while (!stk.isEmpty()) {
                    Frame cur = stk.pop();
                    TreeNode node = cur.node;
                    if (cur.state == 0) {
                        stk.push(new Frame(node, 1));
                        if (node.right != null) {
                            stk.push(new Frame(node.right, 0));
                        }
                        if (node.left != null) {
                            stk.push(new Frame(node.left, 0));
                        }
                        continue;
                    }
                    int l = node.left == null ? 0 : sub.get(node.left);
                    int r = node.right == null ? 0 : sub.get(node.right);
                    int s = node.val + l + r;
                    mx = Math.max(mx, cnt.merge(s, 1, Integer::sum));
                    sub.put(node, s);
                }
            }
            List<Integer> ans = new ArrayList<>();
            for (var e : cnt.entrySet()) {
                if (e.getValue() == mx) {
                    ans.add(e.getKey());
                }
            }
            return ans.stream().mapToInt(i -> i).toArray();
        }
    }
    
    
  • /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
     *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
     *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
     * };
     */
    class Solution {
    public:
        unordered_map<int, int> counter;
        int mx = 0;
    
        vector<int> findFrequentTreeSum(TreeNode* root) {
            mx = INT_MIN;
            dfs(root);
            vector<int> ans;
            for (auto& entry : counter)
                if (entry.second == mx)
                    ans.push_back(entry.first);
            return ans;
        }
    
        int dfs(TreeNode* root) {
            if (!root) return 0;
            int s = root->val + dfs(root->left) + dfs(root->right);
            ++counter[s];
            mx = max(mx, counter[s]);
            return s;
        }
    };
    
    
    // Solution 2
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
     *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
     *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
     * };
     */
    class Solution {
    public:
        vector<int> findFrequentTreeSum(TreeNode* root) {
            unordered_map<int, int> cnt;
            unordered_map<TreeNode*, int> sub;
            int mx = 0;
            vector<pair<TreeNode*, int>> stk{{root, 0}};
            while (!stk.empty()) {
                auto [node, state] = stk.back();
                stk.pop_back();
                if (!node) {
                    continue;
                }
                if (state == 0) {
                    stk.emplace_back(node, 1);
                    if (node->right) {
                        stk.emplace_back(node->right, 0);
                    }
                    if (node->left) {
                        stk.emplace_back(node->left, 0);
                    }
                    continue;
                }
                int l = node->left ? sub[node->left] : 0;
                int r = node->right ? sub[node->right] : 0;
                int s = node->val + l + r;
                mx = max(mx, ++cnt[s]);
                sub[node] = s;
            }
            vector<int> ans;
            for (const auto& [k, v] : cnt) {
                if (v == mx) {
                    ans.push_back(k);
                }
            }
            return ans;
        }
    };
    
    
  • # Definition for a binary tree node.
    # class TreeNode:
    #     def __init__(self, val=0, left=None, right=None):
    #         self.val = val
    #         self.left = left
    #         self.right = right
    class Solution:
        def findFrequentTreeSum(self, root: TreeNode) -> List[int]:
            def dfs(root):
                if root is None:
                    return 0
                left, right = dfs(root.left), dfs(root.right)
                s = root.val + left + right
                counter[s] += 1
                return s
    
            counter = Counter()
            dfs(root)
            mx = max(counter.values())
            return [k for k, v in counter.items() if v == mx]
    
    
    
    # Solution 2
    # Definition for a binary tree node.
    # class TreeNode:
    #     def __init__(self, val=0, left=None, right=None):
    #         self.val = val
    #         self.left = left
    #         self.right = right
    class Solution:
        def findFrequentTreeSum(self, root: Optional[TreeNode]) -> List[int]:
            cnt = Counter()
            sub = {}
            stk = [(root, 0)]
            while stk:
                node, state = stk.pop()
                if node is None:
                    continue
                if state == 0:
                    stk.append((node, 1))
                    stk.append((node.right, 0))
                    stk.append((node.left, 0))
                    continue
                l = sub[id(node.left)] if node.left is not None else 0
                r = sub[id(node.right)] if node.right is not None else 0
                s = l + r + node.val
                cnt[s] += 1
                sub[id(node)] = s
            if not cnt:
                return []
            mx = max(cnt.values())
            return [k for k, v in cnt.items() if v == mx]
    
    
  • /**
     * Definition for a binary tree node.
     * type TreeNode struct {
     *     Val int
     *     Left *TreeNode
     *     Right *TreeNode
     * }
     */
    func findFrequentTreeSum(root *TreeNode) []int {
    	counter := make(map[int]int)
    	mx := 0
    	var dfs func(root *TreeNode) int
    	dfs = func(root *TreeNode) int {
    		if root == nil {
    			return 0
    		}
    		s := root.Val + dfs(root.Left) + dfs(root.Right)
    		counter[s]++
    		if mx < counter[s] {
    			mx = counter[s]
    		}
    		return s
    	}
    	dfs(root)
    	var ans []int
    	for k, v := range counter {
    		if v == mx {
    			ans = append(ans, k)
    		}
    	}
    	return ans
    }
    
    
    // Solution 2
    /**
     * Definition for a binary tree node.
     * type TreeNode struct {
     *     Val int
     *     Left *TreeNode
     *     Right *TreeNode
     * }
     */
    func findFrequentTreeSum(root *TreeNode) (ans []int) {
    	cnt := map[int]int{}
    	sub := map[*TreeNode]int{}
    	mx := 0
    	type frame struct {
    		node  *TreeNode
    		state int
    	}
    	stk := []frame{{root, 0}}
    	for len(stk) > 0 {
    		cur := stk[len(stk)-1]
    		stk = stk[:len(stk)-1]
    		node, state := cur.node, cur.state
    		if node == nil {
    			continue
    		}
    		if state == 0 {
    			stk = append(stk, frame{node, 1})
    			if node.Right != nil {
    				stk = append(stk, frame{node.Right, 0})
    			}
    			if node.Left != nil {
    				stk = append(stk, frame{node.Left, 0})
    			}
    			continue
    		}
    		l, r := 0, 0
    		if node.Left != nil {
    			l = sub[node.Left]
    		}
    		if node.Right != nil {
    			r = sub[node.Right]
    		}
    		s := node.Val + l + r
    		cnt[s]++
    		mx = max(mx, cnt[s])
    		sub[node] = s
    	}
    	for k, v := range cnt {
    		if v == mx {
    			ans = append(ans, k)
    		}
    	}
    	return
    }
    
    
  • /**
     * Definition for a binary tree node.
     * class TreeNode {
     *     val: number
     *     left: TreeNode | null
     *     right: TreeNode | null
     *     constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
     *         this.val = (val===undefined ? 0 : val)
     *         this.left = (left===undefined ? null : left)
     *         this.right = (right===undefined ? null : right)
     *     }
     * }
     */
    
    function findFrequentTreeSum(root: TreeNode | null): number[] {
        const map = new Map<number, number>();
        let max = 0;
        const dfs = (root: TreeNode | null) => {
            if (root == null) {
                return 0;
            }
            const { val, left, right } = root;
            const sum = val + dfs(left) + dfs(right);
            map.set(sum, (map.get(sum) ?? 0) + 1);
            max = Math.max(max, map.get(sum));
            return sum;
        };
        dfs(root);
        const res = [];
        for (const [k, v] of map) {
            if (v === max) {
                res.push(k);
            }
        }
        return res;
    }
    
    
    
    // Solution 2
    /**
     * Definition for a binary tree node.
     * class TreeNode {
     *     val: number
     *     left: TreeNode | null
     *     right: TreeNode | null
     *     constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
     *         this.val = (val===undefined ? 0 : val)
     *         this.left = (left===undefined ? null : left)
     *         this.right = (right===undefined ? null : right)
     *     }
     * }
     */
    
    function findFrequentTreeSum(root: TreeNode | null): number[] {
        const cnt = new Map<number, number>();
        const sub = new Map<TreeNode, number>();
        let mx = 0;
        const stk: [TreeNode | null, number][] = [[root, 0]];
        while (stk.length) {
            const [node, state] = stk.pop()!;
            if (!node) {
                continue;
            }
            if (state === 0) {
                stk.push([node, 1]);
                if (node.right) {
                    stk.push([node.right, 0]);
                }
                if (node.left) {
                    stk.push([node.left, 0]);
                }
                continue;
            }
            const l = node.left ? sub.get(node.left)! : 0;
            const r = node.right ? sub.get(node.right)! : 0;
            const s = node.val + l + r;
            cnt.set(s, (cnt.get(s) ?? 0) + 1);
            mx = Math.max(mx, cnt.get(s)!);
            sub.set(node, s);
        }
        return Array.from(cnt.entries())
            .filter(([_, c]) => c === mx)
            .map(([s, _]) => s);
    }
    
    
  • // Definition for a binary tree node.
    // #[derive(Debug, PartialEq, Eq)]
    // pub struct TreeNode {
    //   pub val: i32,
    //   pub left: Option<Rc<RefCell<TreeNode>>>,
    //   pub right: Option<Rc<RefCell<TreeNode>>>,
    // }
    //
    // impl TreeNode {
    //   #[inline]
    //   pub fn new(val: i32) -> Self {
    //     TreeNode {
    //       val,
    //       left: None,
    //       right: None
    //     }
    //   }
    // }
    use std::rc::Rc;
    use std::cell::RefCell;
    use std::collections::HashMap;
    impl Solution {
        fn dfs(
            root: &Option<Rc<RefCell<TreeNode>>>,
            map: &mut HashMap<i32, i32>,
            max: &mut i32
        ) -> i32 {
            if root.is_none() {
                return 0;
            }
            let node = root.as_ref().unwrap().borrow();
            let sum = node.val + Self::dfs(&node.left, map, max) + Self::dfs(&node.right, map, max);
            map.insert(sum, map.get(&sum).unwrap_or(&0) + 1);
            *max = (*max).max(map[&sum]);
            sum
        }
    
        pub fn find_frequent_tree_sum(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
            let mut map = HashMap::new();
            let mut max = 0;
            let mut res = Vec::new();
            Self::dfs(&root, &mut map, &mut max);
            for (k, v) in map.into_iter() {
                if v == max {
                    res.push(k);
                }
            }
            res
        }
    }
    
    
    
    // Solution 2
    // Definition for a binary tree node.
    // #[derive(Debug, PartialEq, Eq)]
    // pub struct TreeNode {
    //   pub val: i32,
    //   pub left: Option<Rc<RefCell<TreeNode>>>,
    //   pub right: Option<Rc<RefCell<TreeNode>>>,
    // }
    //
    // impl TreeNode {
    //   #[inline]
    //   pub fn new(val: i32) -> Self {
    //     TreeNode {
    //       val,
    //       left: None,
    //       right: None
    //     }
    //   }
    // }
    use std::cell::RefCell;
    use std::collections::HashMap;
    use std::rc::Rc;
    
    impl Solution {
        pub fn find_frequent_tree_sum(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
            let mut cnt: HashMap<i32, i32> = HashMap::new();
            let mut sub: HashMap<usize, i32> = HashMap::new();
            let mut stk = vec![(root, 0)];
            while let Some((node, state)) = stk.pop() {
                if let Some(node) = node {
                    if state == 0 {
                        let (left, right) = {
                            let b = node.borrow();
                            (b.left.clone(), b.right.clone())
                        };
                        stk.push((Some(node), 1));
                        if right.is_some() {
                            stk.push((right, 0));
                        }
                        if left.is_some() {
                            stk.push((left, 0));
                        }
                    } else {
                        let b = node.borrow();
                        let l = b
                            .left
                            .as_ref()
                            .map(|n| sub[&(Rc::as_ptr(n) as usize)])
                            .unwrap_or(0);
                        let r = b
                            .right
                            .as_ref()
                            .map(|n| sub[&(Rc::as_ptr(n) as usize)])
                            .unwrap_or(0);
                        let s = l + r + b.val;
                        *cnt.entry(s).or_insert(0) += 1;
                        drop(b);
                        sub.insert(Rc::as_ptr(&node) as usize, s);
                    }
                }
            }
            let mx = cnt.values().cloned().max().unwrap_or(0);
            cnt.into_iter()
                .filter(|&(_, v)| v == mx)
                .map(|(k, _)| k)
                .collect()
        }
    }
    
    

All Problems

All Solutions