Professional Documents
Culture Documents
Documento PDF-5BC22A29F276-1 PDF
Documento PDF-5BC22A29F276-1 PDF
House of Codes
Apr 10 · 12 min read
Binary Trees are one of the Most Important Data Structures out there. If you
have been following me you would have known that I recently did a 100 days to
Amazon Challenge. As I was solving these problems. I found many similarities
between these interview questions. I would like to share it with you. Free Link
via
100 Days to Amazon — Day 1
100 of the Most Commonly Asked Questions in Amazon. With Code
and Explanation of the Approach.
medium.com
This post is all about making you strong in the fundamental Logic’s that are
used to Solve Binary Tree Problems.
So that when you are in your Interview and you come across a Binary Tree
problem you will know which logic to use and how you could approach that
problem!
Not only you will complete 15 Leetcode Problems. These logic's account to around
30+ Problems in Leetcode. Are you preparing for interviews?
Inorder Traversal
Input: [1,null,2,3]
1
\
2
/
3
Output: [1,3,2]
Recursive Approach
❤
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 List<Integer> ans = new ArrayList<>();
12 public List<Integer> inorderTraversal(TreeNode root) {
13
14 inorder(root);
15
16 return ans;
17 }
18
19 public void inorder(TreeNode root)
20 {
21 if(root == null)
22 return;
23
24 inorder(root.left);
25 ans.add(root.val);
26 inorder(root.right);
27 }
28
29 }
While Inorder Traversing, We traverse to the Left Child then to the Root followed
by the Right Child.
Iterative Version
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 public List<Integer> inorderTraversal(TreeNode root) {
12
13 Stack<TreeNode> st = new Stack<>();
14 List<Integer> ans = new ArrayList<>();
15 TreeNode curr = root;
16
17 while(curr != null || !st.isEmpty())
18 {
18 {
19 while(curr !=null)
20 {
21 st.push(curr);
22 curr = curr.left;
23 }
24 curr = st.pop();
25 ans.add(curr.val);
26 curr =curr.right;
27 }
28 return ans;
29 }
30 }
Algorithm
1. You have got to traverse towards the left end of the tree.
2. Traverse towards the left till you reach a null point. While Doing so add all
these elements to the Stack.
3. After this pop the last left child. Print that value.
5. Repeat these steps till both the Stack is Empty or till you reach a null point.
Preorder Traversal
Input: [1,null,2,3]
1
\
2
/
3
Output: [1,2,3]
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 List<Integer> ans = new ArrayList<>();
12 public List<Integer> preorderTraversal(TreeNode root) {
13
14 preorder(root);
15
16 return ans;
17
18 }
19 public void preorder(TreeNode root)
20 {
21 if(root == null)
22 return;
23
24 ans.add(root.val);
25 preorder(root.left);
26 preorder(root.right);
27
28 }
29 }
While Preorder Traversing, We traverse to the Root First then to the Left Child
followed by the Right Child.
Iterative Version
❤
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 public List<Integer> preorderTraversal(TreeNode root) {
12
13 List<Integer> ans = new ArrayList<>();
14 if(root == null)
15 return ans;
16 Stack<TreeNode> st = new Stack<>();
17 st.push(root);
18 while(!st.isEmpty())
19 {
20 TreeNode curr = st.pop();
21 ans.add(curr.val);
22 if(curr.right != null)
23 st.push(curr.right);
24 if(curr.left != null)
25 st.push(curr.left);
26 }
27 return ans;
28
29 }
30 }
Algorithm
1. Use Stack to Store the Traversal.
5. Think about this: You have got to traverse to the left child and then right
child.
Since we are using a Stack. We have to push the right child 9rst then left child.
So that when you pop, the element will be the Left Child.
Post-Order Traversal
Input: [1,null,2,3]
1
\
2
/
3
Output: [3,2,1]
Recursive Version
❤
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 List<Integer> ans;
12 public List<Integer> postorderTraversal(TreeNode root) {
13 ans = new ArrayList<>();
14 postorder(root);
15
16 return ans;
17 }
18
19 public void postorder(TreeNode root)
20 {
21 if(root == null)
22 return;
23
24 postorder(root.left);
25 postorder(root.right);
26 ans.add(root.val);
27
28 }
29 }
While Post-Order Traversing, We traverse to the Left Child followed by the Right
Child then Root First.
Iterative Version
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 public List<Integer> postorderTraversal(TreeNode root) {
12 List<Integer> res = new ArrayList<>();
13
14 Stack<TreeNode> s = new Stack<>();
15 if(root == null)
16 return res;
17 s.push(root);
18
19 while(!s.isEmpty())
20 {
21 TreeNode curr = s.pop();
22 res.add(curr.val);
23
24 if(curr.left != null)
25 s.push(curr.left);
26
27 if(curr.right != null)
28 s.push(curr.right);
29
30 }
31 Collections.reverse(res);
32 return res;
33
34 }
35 }
3. Here Each time you enter the loop. Add it to the List.
. . .
BFS is used to traverse the Tree by levels. The above tree will be traversed:
1 ->2->3->4->5->6
Given a binary tree, return the level order traversal of its nodes’ values. (i.e,
from left to right, level by level).
For example
Given binary tree [3,9,20,null,null,15,7] ,
3
/ \
9 20
/ \
15 7
[
[3],
[9,20],
[15,7]
]
Code
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 public List<List<Integer>> levelOrder(TreeNode root) {
12 List<List<Integer>> ans = new ArrayList<>();
13 if(root == null)
14 return ans;
15 Queue<TreeNode> q = new LinkedList<>();
16 q.offer(root);
17
18
19 while(!q.isEmpty())
20 {
21 int level = q.size();
22 List<Integer> row = new ArrayList<>();
23
24 for(int i = 0; i < level; i++)
25 {
26 TreeNode curr = q.poll();
27
28 if(curr.left != null)
29 q.offer(curr.left);
30
31 if(curr.right != null)
32 q.offer(curr.right);
33
34 row.add(curr.val);
35
36 }
37
38 ans.add(row);
39
40 }
41 return ans;
42 }
43 }
Algorithm
1. Create a queue that is going to store the next to visit nodes.
4. For each node, you visit. Look whether there is a left or right node. If there is
add it to the Queue.
5. Whenever you are adding new elements to the queue that means you have
entered a new level.
6. So when you traverse out of each level add it to the result set.
Take Some time to understand this Code. You are going to use this concept in
the following Problems. Before Each Problem think of how to apply this
method to solve the program
3
/ \
9 20
/ \
15 7
[
[15,7],
[9,20],
[3]
]
Code
1 /**
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 public List<List<Integer>> levelOrderBottom(TreeNode root) {
12
13 Queue<TreeNode> q = new LinkedList<>();
14 q.offer(root);
15 List<List<Integer>> ans = new ArrayList<>();
16
17 if(root == null)
18 return ans;
19
20 while(!q.isEmpty())
21 {
22 int level = q.size();
23 List<Integer> row = new ArrayList<>();
24 for(int i =0; i < level; i ++)
25 {
26 TreeNode curr = q.poll();
27
28 if(curr.left != null)
29 q.offer(curr.left);
30
31 if(curr.right != null)
32 q.offer(curr.right);
33
34 row.add(curr.val);
35 }
36
37 ans.add(row);
38 }
39
40
41 Collections.reverse(ans);
42
43 return ans;
44 }
45 }
What’s DiXerent?
3
/ \
9 20
/ \
15 7
Code
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
12
13 Queue<TreeNode> q = new LinkedList<>();
14
15 q.offer(root);
16 int dir =0;
17
18 List<List<Integer>> ans = new ArrayList<>();
19
20 if(root == null)
21 return ans;
22
23 while(!q.isEmpty())
24 {
25
26 int level = q.size();
27 List<Integer> row = new ArrayList<>();
28
29 for(int i=0; i < level; i++)
30 {
31 TreeNode curr = q.poll();
32 if(curr.left != null)
33 q.offer(curr.left);
34
35 if(curr.right != null)
36 q.offer(curr.right);
37
38 row.add(curr.val);
39
40
41 }
42
43 if(dir == 0)
44 {
45 ans.add(row);
46 dir = 1;
47 }
47 }
48
49 else if(dir == 1)
50 {
51 Collections.reverse(row);
52 ans.add(row);
53 dir =0;
54
55 }
56
57
58 }
59 return ans;
60
61 }
62 }
Introduce a new variable called dir which is going to indicate the direction in
which you have to add the row to the 2D List.
If the Directions is from Right to Left that is 1. You have to Reverse the Current
Row then add it to the 2D list. Else just add the List.
Example:
Input: [1,2,3,null,5,null,4]
Output: [1, 3, 4]
Explanation:
1 <---
/ \
2 3 <---
\ \
5 4 <--
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 public List<Integer> rightSideView(TreeNode root) {
12 List<Integer> ans = new ArrayList<>();
13 Queue<TreeNode> q = new LinkedList<>();
14
15 if(root == null)
16 return ans;
16 return ans;
17
18 q.offer(root);
19 while(!q.isEmpty())
20 {
21 int level = q.size();
22 int r =0;
23 for(int i =0; i < level; i++)
24 {
25 TreeNode curr = q.poll();
26 r=curr.val;
27 if(curr.left != null)
28 q.offer(curr.left);
29
30 if(curr.right != null)
31 q.offer(curr.right);
32
33 }
34 ans.add(r);
35 }
36 return ans;
37 }
38 }
Explanation
Whenever we traverse the tree by BFS at each level. The Last Element will
represent the Right Side of The Binary Tree.
All you have to make sure is, After each Level, you have to reinitialize the
right element.
Additional Question
Try Solving the Left Side of the Binary Tree and the Bottom Left Tree Element
using BFS. Similar to the method discussed above.
Aggregate Functions
I will work on one Example of Maximum Element.
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 1:
Input: [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.
If you could come up with the Solution here. Then I have Succeeded ❤
Code
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 public int maxLevelSum(TreeNode root) {
12 Queue<TreeNode> q = new LinkedList<>();
13 q.offer(root);
14
15 if(root == null)
16 return 1;
17
18 int max = Integer.MIN_VALUE;
19 int count = 1;
20 int res = 1;
21 while(!q.isEmpty())
22 {
23 int level = q.size();
24 int sum =0;
25 for(int i =0; i < level; i++)
26 {
27 TreeNode curr = q.poll();
28 if(curr.left != null)
29 q.offer(curr.left);
30 if(curr.right != null)
31 q.offer(curr.right);
32 sum += curr.val;
33
34 }
35
36 if(sum > max)
37 {
38 max = sum;
39 res = count;
40 }
41 count++;
42 }
43
44 return res;
45 }
46 }
46 }
This is fairly straightforward. From what you had learned before. You traverse
level by level. At Each Level add the row values and compare them with
maximum value.
If it is greater than max. Change max and store the level. Return the max_sum
level
If you liked this post. How about you give some claps? &
. . .
Equals
Next, we are going to Look into the Binary Tree Equivalent of String Equals.
This Seems Simple but this is the ground for Many Interview Problems two of
which we are going to Look today.
1. Is Mirror?
2. Is Sub-tree?
. . .
First We are going to look at the Equals Function
Aim
Given two binary trees, write a function to check if they are the same or not.
Two binary trees are considered the same if they are structurally identical and
the nodes have the same value.
Example 1:
Input:
1 1
/ \ / \
2 3 2 3
[1,2,3], [1,2,3]
Output: true
Code
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 public boolean isSameTree(TreeNode p, TreeNode q) {
12 if(p == null && q == null)
13 return true;
14
14
15 if(p == null || q == null)
16 return false;
17
18 return p.val == q.val && isSameTree(p.left, q.left) && isSameTree(p.right, q
19
20 }
21 }
Algorithm
1. For Equals Function. Traverse both Trees at the on the same path.
3. Both the nodes are null. One of the nodes is null. Both of them are not null
values.
4. If both of the Nodes are null then they are structurally equivalent.
5. However, If you reach one null node and the other one is not null then they
are not structurally equivalent.
. . .
Is Mirror?
Given a binary tree, check whether it is a mirror of itself (ie, symmetric around
its center).
For example, this binary tree [1,2,2,3,4,4,3] is symmetric:
1
/ \
2 2
/ \ / \
3 4 4 3
Can you apply the Logic that we learned before to solve this problem?
Code
❤
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 public boolean isSymmetric(TreeNode root) {
12
13 return equals(root,root);
14
15 }
16
17 public boolean equals (TreeNode p, TreeNode q)
18 {
19 if(p == null && q ==null)
20 return true;
21
22 if(p == null || q == null)
23 return false;
24
25
26
27 return(p.val == q.val && equals(p.left, q.right) && equals(p.right, q.left));
28
29
30 }
31 }
Algorithm
When you think about it. Instead of two diXerent trees. What you have to do is
Send the Same root to the function.
. . .
Is Sub-tree?
Given two non-empty binary trees s and t, check whether tree t has exactly the
same structure and node values with a sub tree of s.
Example 1:
Given tree s:
3
/ \
4 5
/ \
1 2
Given tree t:
4
/ \
1 2
Return true, because t has the same structure and node values with a subtree of s.
I want you to think of applying this method before proceeding to look at the code
. . .
Code
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 public boolean isSubtree(TreeNode s, TreeNode t) {
12 return Traverse(s,t);
13 }
14
15 public boolean Traverse(TreeNode s, TreeNode t)
16 {
17 return (s!= null) &&(isSameTree(s, t) || Traverse(s.left, t) || Traverse(s
18 }
19
20 public boolean isSameTree(TreeNode s, TreeNode t)
21 {
22 if(s== null && t == null)
23 return true;
24
25 if(s == null || t == null)
26 return false;
27
28 return (s.val == t.val && isSameTree(s.left, t.left) && isSameTree(s.right, t
29 }
30
31 }
31 }
Algorithm
2. Since we are looking for sub-trees. You have got to traverse not only from
the root.
4. Call Equals function for each subtree of the ]rst tree and return true if any
one of them are matching the result.
My favorite free courses to learn data structures and
algorithms in depth
A curated list of some of the best, free online courses to learn Data
Structure and Algorithms for programmers.
medium.com
. . .
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 public boolean isCompleteTree(TreeNode root) {
12 if(root == null)
13 return true;
14
15 Queue<TreeNode> q = new LinkedList<>();
16 q.offer(root);
17
17
18 List<Anode> list = new ArrayList<>();
19 list.add(new Anode(root,1));
20 int code = 1;
21 while(!q.isEmpty())
22 {
23 int level = q.size();
24
25 for(int i =0; i < level; i++)
26 {
27 TreeNode curr = q.poll();
28 if(curr.left!= null)
29 {
30 q.offer(curr.left);
31 list.add(new Anode(curr.left, code*2));
32 }
33
34 if(curr.right!= null)
35 {
36 q.offer(curr.right);
37 list.add(new Anode(curr.right, code*2 +1));
38 }
39
40
41
42 }
43 code++;
44
45
46 }
47
48 for(int i =0; i<list.size(); i++)
49 {
50 System.out.println(list.get(i).code);
51 }
52
53 return list.get(list.size()-1).code == list.size();
54
55
56
56
57 }
58
59 public class Anode{
60 int code;
61 TreeNode node;
62
63 Anode(TreeNode node, int code)
64 {
65 this.node = node;
66 this.code = code;
67 }
68
69 }
70 }
Here you have to convert the given tree into the annotated node.
4. At Each Level, When you are adding a left child to the queue. You will add a
new annotated code value with 2 * x.
5. When you are adding the right child to the queue. You will add a new
annotated code value with 2 *x +1
6. Add the Codes to the result list. At the end of BFS, Check if the last code in the
list is equal to the size of the list.
. . .
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class FindElements {
11 public class Anode{
12 TreeNode node;
13 int code;
14
15 Anode(TreeNode node, int code)
16 {
17 this.node = node;
18 this.code = code;
19 }
20 }
21 Set<Integer> set = new HashSet<>();
22
23 public FindElements(TreeNode root) {
24
25 Queue<Anode> q = new LinkedList<>();
26 q.offer(new Anode(root, 0));
27 while(!q.isEmpty())
28 {
29 int level = q.size();
30 for(int i =0; i <level; i++)
31 {
32 Anode curr = q.poll();
33 set.add(curr.code);
34 if(curr.node.left != null)
35 {
36 q.offer(new Anode(curr.node.left, curr.code * 2 +1));
37 }
38
39 if(curr.node.right != null)
40 {
40 {
41 q.offer(new Anode(curr.node.right, curr.code * 2 + 2));
42 }
43
44 }
45
46 }
47
48 }
49 public boolean find(int target) {
50 return set.contains(target);
51 }
52 }
You are traveling towards the depth of the tree. Hence the name.
This series is all about using an Algorithm to solve a bunch of Binary Trees
problems that have been asked in Coding Interviews. (FAANG Companies)
DFS
Algorithm
1. DFS Traverses towards the depth.
2. Send the Root node to a function (dfs) in which we are gonna traverse the
Tree in DFS.
4. First Go towards the left side. Call the Same Function just change the
parameter to the Left child of the node.
1→2→4
5. We would have Reached till 4.
6. Now we have got to traverse towards the right. Go to the deepest node. Call
the Same Function but use the right child of the node as the parameter.
4→5→6
7. The ]rst element that is going to be printed is 6 Since that is the deepest node
of the tree. Recursively you will be going back.
. . .
4
/ \
2 7
/ \ / \
1 3 6 9
Output
4
/ \
7 2
/ \ / \
9 6 3 1
Code
❤
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 public TreeNode invertTree(TreeNode root) {
12 if(root == null)
13 return null;
14
15 TreeNode left = invertTree(root.left);
16 TreeNode right = invertTree(root.right);
17
18 root.left = right;
19 root.right = left;
20
21
22 return root;
23 }
24
25
26 }
Algorithm
1. Traverse the Tree in DFS order.
3. Make the current node’s left to be the right child of the node.
4. Make the current node’s right to be the left child of the node
. . .
2) Maximum depth of The Tree
Given a binary tree, ]nd its maximum depth.
The maximum depth is the number of nodes along the longest path from the
root node down to the farthest leaf node.
Example
Given binary tree [3,9,20,null,null,15,7] ,
3
/ \
9 20
/ \
15 7
Now for Maximum Depth of the Tree. When you reach null node return the
height as 1. Traverse the Left and Right as DFS traversal does.
Code
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 int max = Integer.MIN_VALUE;
12 public int maxDepth(TreeNode root) {
13
14 height(root);
15
16 return max == Integer.MIN_VALUE ? 0 : max;
17 }
18
19 public int height(TreeNode root)
20 {
21 if(root == null)
22 return 1;
23
24 int L = height(root.left);
25 int R = height(root.right);
25 int R = height(root.right);
26
27 max = Math.max(max, Math.max(L,R));
28 return Math.max(L,R) +1;
29
30 }
31 }
After we have run the dfs traversal. Return the Max Value
3) Diameter of the Binary Tree
Given a binary tree, you need to compute the length of the diameter of the tree.
The diameter of a binary tree is the length of the longest path between any two
nodes in a tree. This path may or may not pass through the root.
Example:
Given a binary tree
1
/ \
2 3
/ \
4 5
Note: The length of the path between two nodes is represented by the number of
edges between them.
Code
1 /**
❤
1 /**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 * int val;
5 * TreeNode left;
6 * TreeNode right;
7 * TreeNode(int x) { val = x; }
8 * }
9 */
10 class Solution {
11 int dia = 0;
12 public int diameterOfBinaryTree(TreeNode root) {
13 dfs(root);
14 return dia;
15 }
16
17 public int dfs(TreeNode root)
18 {
19
20 if(root == null)
21 return 0;
22
23 int left = dfs(root.left);
24 int right = dfs(root.right);
25
26 dia = Math.max(dia , left+right);
27
28 return Math.max(left, right) + 1;
29
30 }
31 }
Algorithm
1. Use the Same DFS Approach to Traverse the tree.
4. Since at each node we have the distance from that node to the left_deepest
node and the right_deepest node. What Constitutes a Diameter of the Tree
Conclusion
Don’t forget to hit the follow button ✅
to receive updates when we post new
coding challenges. Tell us how you solved this problem in the comments section
below. We (
would be thrilled to read them.
Author : Akshay Ravindran