diff --git a/Backtracking Algorithms/Leaf Similar Tree/Program_leaf.c b/Backtracking Algorithms/Leaf Similar Tree/Program_leaf.c new file mode 100644 index 00000000..0cc9120c --- /dev/null +++ b/Backtracking Algorithms/Leaf Similar Tree/Program_leaf.c @@ -0,0 +1,90 @@ +#include +#include +#include + +// Definition for a binary tree node. +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; +}; + +// Function to create a new tree node +struct TreeNode* createNode(int val) { + struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode)); + newNode->val = val; + newNode->left = NULL; + newNode->right = NULL; + return newNode; +} + +// Function to collect leaf nodes in the tree +void collectLeaves(struct TreeNode* root, int* leaves, int* index) { + if (root == NULL) { + return; + } + // If it's a leaf node, add its value to the leaves array + if (root->left == NULL && root->right == NULL) { + leaves[(*index)++] = root->val; + return; + } + // Recur for left and right subtrees + collectLeaves(root->left, leaves, index); + collectLeaves(root->right, leaves, index); +} + +// Function to check if two trees are leaf-similar +bool leafSimilar(struct TreeNode* root1, struct TreeNode* root2) { + // Assuming a maximum of 100 leaves for simplicity + int leaves1[100], leaves2[100]; + int index1 = 0, index2 = 0; + + // Collect leaves of both trees + collectLeaves(root1, leaves1, &index1); + collectLeaves(root2, leaves2, &index2); + + // Compare the number of leaves + if (index1 != index2) { + return false; + } + + // Compare the leaf values + for (int i = 0; i < index1; i++) { + if (leaves1[i] != leaves2[i]) { + return false; + } + } + + return true; +} + +// Main function to test the leafSimilar function +int main() { + // Create first tree + struct TreeNode* root1 = createNode(3); + root1->left = createNode(5); + root1->right = createNode(1); + root1->left->left = createNode(6); + root1->left->right = createNode(2); + root1->left->right->left = createNode(9); + root1->left->right->right = createNode(4); + + // Create second tree + struct TreeNode* root2 = createNode(7); + root2->left = createNode(2); + root2->right = createNode(1); + root2->left->left = createNode(6); + root2->left->right = createNode(5); + + // Check if the trees are leaf-similar + if (leafSimilar(root1, root2)) { + printf("The trees are leaf-similar.\n"); + } else { + printf("The trees are not leaf-similar.\n"); + } + + // Free allocated memory (not shown for brevity) + // You should implement a function to free the tree nodes. + + return 0; +} \ No newline at end of file diff --git a/Backtracking Algorithms/Leaf Similar Tree/Readme.md b/Backtracking Algorithms/Leaf Similar Tree/Readme.md new file mode 100644 index 00000000..a1d8bccc --- /dev/null +++ b/Backtracking Algorithms/Leaf Similar Tree/Readme.md @@ -0,0 +1,46 @@ +## Leaf-Similar Tree + +# Problem Description +In the given problem, we are asked to compare two binary trees to check if they are 'leaf-similar'. Binary trees are a type of data structure in which each node has at most two children, referred to as the left child and the right child. A leaf node is a node with no children. The 'leaf value sequence' is the list of values of these leaf nodes read from left to right. Two binary trees are considered 'leaf-similar' if the sequences that of their leaf values are identical. + +# Solution Approach +The solution is implemented in Python, and it focuses on a Depth-First Search (DFS) approach to traverse through the binary trees. The implementation defines a nested function dfs within the leafSimilar method, with the purpose of performing the actual DFS traversal, searching the entire tree for its leaves, and building the leaf sequence. + +Here's the step-by-step breakdown of the algorithm: + +The dfs function is defined, which takes a single argument, root, representing the current node in the tree. +Upon each invocation of dfs, the function first checks if the current root node is None. If it is, it returns an empty list as there are no leaves to gather from a None subtree. +If the current node is not None, the dfs function first recursively calls itself with root.left and root.right to search through the entire left and right subtrees. +The leaves are gathered by this part of the code: ans = dfs(root.left) + dfs(root.right). This code concatenates the left and right subtree leaves into one sequence. +Finally, the function checks if the node is a leaf node, that means both root.left and root.right are None. If it is a leaf, it returns a list containing the leaf's value: [root.val]. If the node is not a leaf, it returns the concatenated list of leaf values from both the left and right subtrees. +The main function leafSimilar calls the dfs function for both root1 and root2 trees, collecting the sequences of leaf values as lists. +The solution concludes by comparing these two lists with dfs(root1) == dfs(root2). If they are identical, it means that the leaf value sequences are the same, and therefore the two trees are considered leaf-similar and True is returned. If the sequences differ in any way, the function returns False. + +# Examples: + +Input: Roots of below Binary Trees + 1 + / \ + 2 3 + / / \ + 4 6 7 + + 0 + / \ + 5 8 + \ / \ + 4 6 7 +Output: same +Leaf order traversal of both trees is 4 6 7 + +Input: Roots of below Binary Trees + 0 + / \ + 1 2 + / \ + 8 9 + +# Time Complexity and Space Complexity +The time complexity of the algorithm is determined by the depth-first search (DFS) function, which visits every node in the binary tree exactly once. Therefore, the time complexity is O(N+M), where N is the number of nodes in the first tree and M is the number of nodes in the second tree. + +The space complexity is mainly governed by the call stack of the recursive DFS calls and the space used to store the leaf values. In the worst case, the depth of the recursion could be O(H1+H2), where H1 is the maximum height of the first tree and H2 is the maximum height of the second tree, if the trees are highly skewed. \ No newline at end of file