Showing posts with label Binary Tree. Show all posts
Showing posts with label Binary Tree. Show all posts

Friday, July 26, 2024

[Microsoft][GFG] Tree Boundary Traversal in anticlockwise direction

Problem: Given a Binary Tree, find its Boundary Traversal. The traversal should be in the following order: 

  • Left boundary nodes: defined as the path from the root to the left-most node ie- the leaf node you could reach when you always travel preferring the left subtree over the right subtree. 
  • Leaf nodes: All the leaf nodes except for the ones that are part of left or right boundary.
  • Reverse right boundary nodes: defined as the path from the right-most node to the root. The right-most node is the leaf node you could reach when you always travel preferring the right subtree over the left subtree. Exclude the root from this as it was already included in the traversal of left boundary nodes.

Note: If the root doesn't have a left subtree or right subtree, then the root itself is the left or right boundary. 

Example:

Input:
        1 
      /   \
     2     3  
    / \   / \ 
   4   5 6   7
      / \
     8   9
   
Output: 1 2 4 8 9 6 7 3
Explanation:
Input:
            1
           /
          2
        /  \
       4    9
     /  \    \
    6    5    3
             /  \
            7     8

Output: 1 2 4 6 5 7 8
Explanation:













As you can see we have not taken the right subtree.


Approach: We can solve this problem in four steps given the nature of the problem:

  1. Add root to result.
  2. Preorder traversal of left subtree. If left child is available then do not go for right child. Ignore the leaves.
  3. Inorder traversal of leaves if root is not leaf.
  4. Postorder traversal of right subtre. If right child is available then do not go for left child. Ignore the leaves.
That's all!

Implementation in C#:

class BinaryTreeNode

{

    public BinaryTreeNode Left {get; set;}

    public BinaryTreeNode Right {get; set;}

    public int Value {get; set;}

    public BinaryTreeNode(int val,

                                           BinaryTreeNode left = null,

                                           BinaryTreeNode right = null)

    {

        this.Left = left;

        this.Right = right;

        this.Value = val;

    }

}


class BinaryTree

{

    public List<int> BoundaryTraversal()

    {

        List<int> result = new List<int>();

        if (this.Root == null)

        {

            return result;

        }

        result.Add(this.Root.Value);

        this.TraverseLeftBoundary(this.Root.Left, result);

        // Avoid leaf traversing if root itself is leaf

        if (this.Root.Left != null || this.Root.Right != null)

        {

            this.TraverseLeaves(this.Root, result);

        }

        this.TraverseRightBoundary(this.Root.Right, result);

        return result;

    }

    

    private void TraverseLeftBoundary(BinaryTreeNode node,

                                                              List<int> result)

    {

        if (node == null ||

            (node.Left == null && node.Right == null))

        {

            return;

        }

        if (node.Left != null)

        {

            result.Add(node.Value);

            this.TraverseLeftBoundary(node.Left, result);

        }

        else

        {

            result.Add(node.Value);

            this.TraverseLeftBoundary(node.Right, result);

        }

    }

    

    private void TraverseLeaves(BinaryTreeNode node,

                                                   List<int> result)

    {

        if (node == null)

        {

            return;

        }

        this.TraverseLeaves(node.Left, result);

        if (node.Left == null && node.Right == null)

        {

            result.Add(node.Value);

        }

        this.TraverseLeaves(node.Right, result);

    }

    

    private void TraverseRightBoundary(BinaryTreeNode node,

                                                                List<int> result)

    {

        if (node == null ||

            (node.Left == null && node.Right == null))

        {

            return;

        }

        if (node.Right != null)

        {

            this.TraverseRightBoundary(node.Right, result);

            result.Add(node.Value);

        }

        else

        {

            this.TraverseRightBoundary(node.Left, result);

            result.Add(node.Value);

        }

    }

    public BinaryTreeNode Root {get; set;}

}


Complexity: O(n)

Monday, March 11, 2024

[LeetCode] Maximum Level Sum of a Binary Tree

Problem: Given the root of a binary tree, the level of its root is 1, the level of its children is 2, and so on.

Return the smallest level x such that the sum of all the values of nodes at level x is maximal.

Example:

Input: root = [1,7,0,7,-8,null,null]
Output: 2
Explanation: 
Level 1 sum = 1.
Level 2 sum = 7 + 0 = 7.
Level 3 sum = 7 + -8 = -1.
So we return the level with the maximum sum which is level 2.
Input: root = [989,null,10250,98693,-89388,null,null,null,-32127]
Output: 2


Approach: It's a straight forward problem to solve. We will do level order traversal and take the sum of all the elements at each level. We will compare this sum of current level with max level sum if current sum is strictly (need to return minimum level) greater than than maximum sum than we update the max level sum and max level.

That's all!


Implementation in C#:

    public int MaxLevelSum(TreeNode root)
    {
        if (root == null)
        {
            return 0;
        }

        int maxLevel = 0, maxLevelSum = int.MinValue;
        Queue<TreeNode> queue = new Queue<TreeNode>();
        queue.Enqueue(root);
        int currLevel = 1;
        while(queue.Count != 0)
        {
            int size = queue.Count;
            int currLevelSum = 0;
            for (int i = 0; i < size; ++i)
            {
                var node = queue.Dequeue();
                currLevelSum += node.val;
                if (node.left != null)
                {
                    queue.Enqueue(node.left);
                }
                if (node.right != null)
                {
                    queue.Enqueue(node.right);
                }
            }
            if (currLevelSum > maxLevelSum)
            {
                maxLevelSum = currLevelSum;
                maxLevel = currLevel;
            }
            ++currLevel;
        }
        return maxLevel;
    }


Complexity: O(n)

[LeetCode] Longest ZigZag Path in a Binary Tree

Problem: You are given the root of a binary tree.

A ZigZag path for a binary tree is defined as follow:

  • Choose any node in the binary tree and a direction (right or left).
  • If the current direction is right, move to the right child of the current node; otherwise, move to the left child.
  • Change the direction from right to left or from left to right.
  • Repeat the second and third steps until you can't move in the tree.

Zigzag length is defined as the number of nodes visited - 1. (A single node has a length of 0).

Return the longest ZigZag path contained in that tree.

Example:

Input: root = [1,null,1,1,1,null,null,1,1,null,1,null,null,null,1]
Output: 3
Explanation: Longest ZigZag path in blue nodes (right -> left -> right).

Input: root = [1,1,1,null,1,null,null,1,1,null,1]
Output: 4
Explanation: Longest ZigZag path in blue nodes (left -> right -> left -> right).
Input: root = [1]
Output: 0


Approach: We can use pre order traversal here. At every node we have two choices:

  1. We can go to opposite direction i.e. if the current direction is left that is we have visited a left child, we can go to child of opposite direction which is right child of current node and we can increment the current path length. Same for right direction child too where we can go to left childe and increment the current path length.
  2. We can go to same direction child and make current path length as 0 so that we can calculate the path length with root as current node.

In the end we can take maximum of above two lengths and that will be our answer.


Implementation in C#:

    public int LongestZigZag(TreeNode root)
    {
        if (root == null)
        {
            return 0;
        }
        return Math.Max(this.LongestZigZagPath(root.left, 0, true),
                        this.LongestZigZagPath(root.right, 0, false));
    }

    private int LongestZigZagPath(TreeNode node,
                                   int currPathLen,
                                   bool isLeft)
    {
        if (node == null)
        {
            return currPathLen;
        }
        return Math.Max(this.LongestZigZagPath(node.left,
                                               isLeft ? 0 : currPathLen + 1,
                                               true),
                        this.LongestZigZagPath(node.right,
                                               isLeft ? currPathLen + 1 : 0,
                                               false));
    }

Compexity: O(n)

Friday, March 8, 2024

[LeetCode] Leaf-Similar Trees

Problem: Consider all the leaves of a binary tree, from left to right order, the values of those leaves form a leaf value sequence.

For example, in the given tree above, the leaf value sequence is (6, 7, 4, 9, 8).

Two binary trees are considered leaf-similar if their leaf value sequence is the same.

Return true if and only if the two given trees with head nodes root1 and root2 are leaf-similar.

Example:

Input: root1 = [3,5,1,6,2,9,8,null,null,7,4], root2 = [3,5,1,6,7,4,2,null,null,null,null,null,null,9,8]
Output: true

Input: root1 = [1,2,3], root2 = [1,3,2]
Output: false


Approach: We can use pre order traversal to store all the leaf in a list. We will run this traversal for both the trees and in the end we will compare both these lists. If these lists are same then we return true; false otherwise.


Implementation in C#:

    public bool LeafSimilar(TreeNode root1, TreeNode root2)
    {
        var leafSq1 = new List<int>();
        var leafSq2 = new List<int>();
        this.GetLeafSequence(root1, leafSq1);
        this.GetLeafSequence(root2, leafSq2);
        return leafSq1.SequenceEqual(leafSq2);
    }

    private void GetLeafSequence(TreeNode node, List<int> result)
    {
        if (node == null)
        {
            return;
        }
        if (node.left == null && node.right == null)
        {
            result.Add(node.val);
            return;
        }
        this.GetLeafSequence(node.left, result);
        this.GetLeafSequence(node.right, result);
    }

Complexity: O(n)

Monday, September 26, 2022

[LeetCode] Find Bottom Left Tree Value

Problem: Given the root of a binary tree, return the leftmost value in the last row of the tree.

Example:

Input: root = [2,1,3]
Output: 1
Input: root = [1,2,3,4,null,5,6,null,null,7]
Output: 7


Approach: We can use Level Order Traversal here. Basically while doing level order traversal, we can store the first element of the current level in a variable which is basically the left most element of that particular level in the tree.

In that way when the traversal ends, we will have the left most element of the last level.


Implementation in C#:

    public int FindBottomLeftValue(TreeNode root) 

    {

        if (root == null)

        {

            return -1;

        }

        Queue<TreeNode> queue = new Queue<TreeNode>();

        queue.Enqueue(root);

        int leftMostValue = -1;

        while(queue.Count > 0)

        {

            int queueSize = queue.Count;

            for (int i = 0; i < queueSize; ++i)

            {

                TreeNode node = queue.Dequeue();

                if (i == 0)

                {

                    leftMostValue = node.val;

                }

                if (node.left != null)

                {

                    queue.Enqueue(node.left);

                }    

                if (node.right != null)

                {

                    queue.Enqueue(node.right);

                }

            }

        }

        return leftMostValue;

    }


Complexity: O(n)

[LeetCode] Most Frequent Subtree Sum

Problem: 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:

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

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

Approach: We can use Preorder traversal here to solve this question. Approach is straight forward, can be understood easily by just looking at the implementation.


Implementation in C#:

    public int[] FindFrequentTreeSum(TreeNode root) 

    {

        if (root == null)

        {

            return null;

        }

        Dictionary<int, int> sumFreqMap = new Dictionary<int, int>();

        this.FindFrequentTreeSumPreOrder(root, sumFreqMap);

        HashSet<int> result = new HashSet<int>();

        int maxFreq = 0;

        foreach (var sumItem in sumFreqMap)

        {

            if (maxFreq < sumItem.Value)

            {

                result.Clear();

                result.Add(sumItem.Key);

                maxFreq = sumItem.Value;

            }

            else if (maxFreq == sumItem.Value)

            {

                result.Add(sumItem.Key);

            }

        }

        return result.ToArray();

    }

    

    public int FindFrequentTreeSumPreOrder(TreeNode node, Dictionary<int, int> sumFreqMap)

    {

        if (node == null)

        {

            return 0;

        }

        if (node.left == null && node.right == null)

        {

            if (!sumFreqMap.ContainsKey(node.val))

            {

                sumFreqMap[node.val]  = 0;

            }

            ++sumFreqMap[node.val];

            return node.val;

        }

        int leftSum = FindFrequentTreeSumPreOrder(node.left, sumFreqMap);

        int rightSum = FindFrequentTreeSumPreOrder(node.right, sumFreqMap);

        int subTreeSum = node.val + leftSum + rightSum;

        if (!sumFreqMap.ContainsKey(subTreeSum))

        {

            sumFreqMap[subTreeSum]  = 0;

        }

        ++sumFreqMap[subTreeSum];

        return subTreeSum;

    }


Complexity: O(n)

Tuesday, October 19, 2021

[LeetCode] Cousins in Binary Tree

Problem: Given the root of a binary tree with unique values and the values of two different nodes of the tree x and y, return true if the nodes corresponding to the values x and y in the tree are cousins, or false otherwise.

Two nodes of a binary tree are cousins if they have the same depth with different parents.

Note that in a binary tree, the root node is at the depth 0, and children of each depth k node are at the depth k + 1.

Example:


Input: root = [1,2,3,4], x = 4, y = 3
Output: false


Input: root = [1,2,3,null,4,null,5], x = 5, y = 4
Output: true

Input: root = [1,2,3,null,4], x = 2, y = 3
Output: false

Constraints:

  • The number of nodes in the tree is in the range [2, 100].
  • 1 <= Node.val <= 100
  • Each node has a unique value.
  • x != y
  • x and y are exist in the tree.


Approach: We can use level order traversal to solve this question. Basically if both x and y are on the same level means both have the same depth.

Now while inserting current node's left and right in the queue, we can check left and right nodes have the value x and y. If yes, then we can return false as parent of x and y is same. 


Implementation in C#:

    public bool IsCousins(TreeNode root, int x, int y) 

    {

        bool foundX = false, foundY = false;

        Queue<TreeNode> queue = new Queue<TreeNode>();

        queue.Enqueue(root);

        while(queue.Count > 0)

        {

            int size = queue.Count;

            for (int i = 0; i < size; ++i)

            {

                TreeNode node = queue.Dequeue();

                if (node.val == x)

                {

                    foundX = true;

                }

                else if (node.val == y)

                {

                    foundY = true;

                }

                if (node.left != null && node.right != null)

                {

                    // Check for same parent

                    if ((node.left.val == x && node.right.val == y) 

                        || (node.left.val == y && node.right.val == x))

                    {

                        return false;

                    }

                }

                if (node.left != null)

                {

                    queue.Enqueue(node.left);

                }  

                if (node.right != null)

                {

                    queue.Enqueue(node.right);

                }

            }  

            if (foundX && foundY)

            {

                return true;

            }

            else if (foundX || foundY)

            {

                return false;

            }

        }        

        return false;

    }


Complexity: O(n)

Friday, September 3, 2021

[Amazon Question] Maximum Average Subtree

Problem: Given the root of a binary tree, find the maximum average value of any subtree of that tree. 

A subtree of a tree is any node of that tree plus all its descendants. The average value of a tree is the sum of its values, divided by the number of nodes.

Example:

Input: Input = [5,6,1]
Output: 6
Explanation: 
For the subtree with root as 5, the average is (5 + 6 + 1) / 3 = 4
For the subtree with root as 6, the average is 6 / 1 = 6 and similarly for subtree with root as 1, the average is 1.
The answer is 6 as it is the maximum of all the above 3 averages.


Approach: We can use post-order traversal here as if we go by bottom-up approach, we will get the average at each and every node and then we can just store the maximum of all the averages. We need to write a function which will return the sum and the number of nodes (of the subtree) but we can have a ref parameter which can then be used for maintaining the maximum average.


Implementation in C#:

    public double MaximumAverageSubtree()

    {

        if (this.Root == null)

        {

            return 0;

        }

        double maxAverage = 0;        

        this.MaximumAverageSubtree(this.Root, ref maxAverage);

        return maxAverage;

    }

    

    private double[] MaximumAverageSubtree(BinaryTreeNode node, ref double maxAverage)

    {

        if (node == null)

        {

            return new double[] {0, 0};

        }

        double[] leftSumAndCount = this.MaximumAverageSubtree(node.LeftNode, ref maxAverage);

        double[] rightSumAndCount = this.MaximumAverageSubtree(node.RightNode, ref maxAverage);

        double sum = leftSumAndCount[0] + rightSumAndCount[0] + node.Value;

        double count = leftSumAndCount[1] + rightSumAndCount[1] + 1;

        double average = sum / count;

        if (average > maxAverage)

        {

            maxAverage = average;

        }        

        return new double[] {sum, count};

    }


Complexity: O(n)

Monday, August 23, 2021

[Google Question] Given a binary tree with string stored leaf node and number of characters in left subtree stored in other nodes, get the substring given index and length.

Problem: You are given a binary tree in which every leaf node has a string and other nodes have the number of characters in their left subtree.  

Given an index and length, return the substring from the binary tree. 

Example:

Chart

Description automatically generated

Input: Tree: above tree, index = 2, length = 10
Output: As pointed in the image "cdefghijkl"
Explanation: If you see the string is "abcdefghilmno", Its substring (2, 10) is "cdefghijkl".


Approach: We can use preorder traversal here. We need to first find the character at given index. Once we find that character, after that we don't need index (we can make it 0) as we just need "length" number of characters.  

Look at the implementation to understand the approach in detail.


Implementation in C#:

      public static string GetString(BinaryTreeStringNode root, int index, int len) 

        { 

            if (root == null) 

            { 

                return string.Empty; 

            } 

            return GetStringInternal(root, ref index, len); 

        } 


        private static string GetStringInternal(BinaryTreeStringNode node, ref int index, int len) 

        { 

            if (node == null) 

            { 

                return string.Empty; 

            } 

            // Got the leaf node, get the substring 

            if (node.Left == null && node.Right == null) 

            { 

                string result = node.Value.Substring(index, len); 

                // Get the starting point, now make index 0 as we just need 'len' number of chars 

                index = 0; 

                return result; 

            } 

            int leftCharsLength = int.Parse(node.Value); 

            // No need to go to left subtree 

            if (leftCharsLength <= index) 

            { 

                index = index - leftCharsLength; 

                return GetStringInternal(node.Right, ref index, len); 

            } 

            // No need to go to right subtree 

            if (leftCharsLength >= index + len) 

            { 

                return GetStringInternal(node.Left, ref index, len); 

            } 

            int numCharsFoundInLeftTree = leftCharsLength - index; 

            return GetStringInternal(node.Left, ref index, numCharsFoundInLeftTree) + GetStringInternal(node.Right, ref index, len - numCharsFoundInLeftTree); 

        }


Complexity: O(n) assuming string operation will take constant time.