Leetcode日练笔记41 [二叉树recursion专题] #250 Count Univalue Subtrees /Medium {Python}

Given the root of a binary tree, return the number of uni-value 

subtrees

.

uni-value subtree means all nodes of the subtree have the same value.

Example 1:

Leetcode日练笔记41 [二叉树recursion专题] #250 Count Univalue Subtrees /Medium {Python}_第1张图片

Input: root = [5,1,5,5,5,null,5]
Output: 4

Example 2:

Input: root = []
Output: 0

Example 3:

Input: root = [5,5,5,5,5,null,5]
Output: 6

Constraints:

  • The number of the node in the tree will be in the range [0, 1000].
  • -1000 <= Node.val <= 1000

Thought process:

Instinctively I take the main funciton countUnivalSubtrees as the one that should be recurred. So I divide the function into usual parts: one for base case which has no child nodes, automatically being a unival subtree, therefore counting as one; the rest part for recursive. 

# 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 countUnivalSubtrees(self, root: Optional[TreeNode]) -> int:
        if not root: return 0
        
        if not root.left and not root.right: return 1
        
        if not root.left:
            if root.right.val == root.val: 
                return 1 + self.countUnivalSubtrees(root.right)
            else:
                return self.countUnivalSubtrees(root.right)
        
        if not root.right:
            if root.left.val == root.val: 
                return 1 + self.countUnivalSubtrees(root.left)
            else:
                return self.countUnivalSubtrees(root.left)
        
        if root.right.val == root.val and root.left.val == root.val:
            return 1 + self.countUnivalSubtrees(root.right) + self.countUnivalSubtrees(root.left)
        else:
            return self.countUnivalSubtrees(root.right) + self.countUnivalSubtrees(root.left)
        

However, it misses the scenerio that even when the node of interest has the same value as its child node, it doesn't necessarily mean its child node itself is also a unival subtree. In such case, the node of interest may violate the rule of being a unival subree. So we can't use this approach.

Just like the graph shown below. This approach takes the root node 1 as unival subtree bc both its children nodes have the same value as it, which should not be by definition.

Leetcode日练笔记41 [二叉树recursion专题] #250 Count Univalue Subtrees /Medium {Python}_第2张图片

Therefore, we have to separate the responsibilities: 1)identify whether the node of interest is a unival subtree by traversing all its children nods n comparing their value; 2) count the nodes that are satisfied such criteria.

# 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 countUnivalSubtrees(self, root: Optional[TreeNode]) -> int:
        self.count = 0

        def is_a_uni_value_subtree(node)-> bool:

            if not node: return True
            
            isLeftUniValue = is_a_uni_value_subtree(node.left)
            isRightUniValue = is_a_uni_value_subtree(node.right)

            if isLeftUniValue and isRightUniValue:
                if node.left and node.left.val != node.val:
                    return False
                if node.right and node.right.val != node.val:
                    return False

                self.count += 1
                return True
            
            return False

        is_a_uni_value_subtree(root)
        return self.count
   

Explanation:
 

Here, the recursive calls are part of a conditional and statement. The nature of the and operator in Python (and many other languages) is short-circuiting. This means that if the first condition (is_a_uni_value_subtree(node.left)) evaluates to False, the second condition (is_a_uni_value_subtree(node.right)) will not be evaluated at all.

This short-circuiting can lead to parts of the tree not being visited. Specifically, if any node's left subtree is not a uni-value subtree, the right subtree won't even be checked, leading to potential uni-value subtrees being missed.

So, in the second code, the recursive exploration of the tree can be prematurely halted due to the short-circuiting behavior of the and operator, leading to a different (and likely incorrect) count of uni-value subtrees.

That's why we need to run both left child node and right child node first then put them into the conditional statement. So that we won't miss counting the right child node even the left child node is not a unival subtree.

你可能感兴趣的:(算法,leetcode,数据结构,python)