|
| 1 | +/* |
| 2 | + Write a function that takes in a Binary Tree and returns if that tree is symmetrical. A tree is symmetrical |
| 3 | + if the left and right subtrees are mirror images of each other. |
| 4 | +
|
| 5 | + Explanation: |
| 6 | +
|
| 7 | + 1. The code defines a class `BinaryTree` representing a binary tree node. It has an `int` value and pointers |
| 8 | + to its left and right children. |
| 9 | + 2. The `SymmetricalTree` function is the main entry point. It calls the helper function `treesAreMirrored` |
| 10 | + to check if the left and right subtrees are mirrored. |
| 11 | + 3. The `treesAreMirrored` function checks if two binary trees are mirrored. It uses recursion to compare |
| 12 | + corresponding nodes in the left and right subtrees. |
| 13 | + 4. In the `treesAreMirrored` function, the base case checks if both the left and right trees are non-null |
| 14 | + and have the same value. If so, it recursively checks if their subtrees are mirrored. |
| 15 | + 5. If either the left or right tree is null or their values are not equal, they are not mirrored. |
| 16 | + If both the left and right trees are null, they are considered mirrored. |
| 17 | + 6. In the `main` function, a binary tree is created for testing purposes. |
| 18 | + 7. The `SymmetricalTree` function is called to check if the binary tree is symmetrical. |
| 19 | + 8. The result is printed to the console. |
| 20 | + 9. Memory cleanup is performed by deleting the dynamically allocated nodes. |
| 21 | +
|
| 22 | + The time and space complexity of the given code snippet can be analyzed as follows: |
| 23 | +
|
| 24 | + 1. Time Complexity: |
| 25 | + - The `SymmetricalTree` function calls the `treesAreMirrored` function, which performs a recursive traversal of the binary tree. |
| 26 | + - In the worst case, the recursion visits each node once, so the time complexity is O(N), where N is the number of nodes in the tree. |
| 27 | +
|
| 28 | + 2. Space Complexity: |
| 29 | + - The space complexity is determined by the maximum depth of the recursion stack. |
| 30 | + - In the worst case, the binary tree is linear, resulting in a recursion depth of N, where N is the number of nodes in the tree. |
| 31 | + - Therefore, the space complexity is O(N) due to the recursion stack usage. |
| 32 | +
|
| 33 | + It's important to note that the space complexity can be optimized by using an iterative approach instead of recursion. By using an iterative algorithm that leverages a stack or queue to perform a level-order traversal, we can achieve a space complexity of O(W), where W is the maximum width (number of nodes at the same level) of the binary tree. |
| 34 | +
|
| 35 | +*/ |
| 36 | +#include <iostream> |
| 37 | + |
| 38 | +using namespace std; |
| 39 | + |
| 40 | +// This is an input class. Do not edit. |
| 41 | +class BinaryTree { |
| 42 | +public: |
| 43 | + int Value; |
| 44 | + BinaryTree* Left; |
| 45 | + BinaryTree* Right; |
| 46 | +}; |
| 47 | + |
| 48 | +// SymmetricalTree checks if a binary tree is symmetrical. |
| 49 | +bool SymmetricalTreeRecursive(BinaryTree* tree) { |
| 50 | + // Call the helper function to check if the left and right subtrees are mirrored. |
| 51 | + return treesAreMirrored(tree->Left, tree->Right); |
| 52 | +} |
| 53 | + |
| 54 | +// treesAreMirrored checks if two binary trees are mirrored. |
| 55 | +bool treesAreMirrored(BinaryTree* left, BinaryTree* right) { |
| 56 | + // Base case: If both left and right trees are non-null and have the same value, |
| 57 | + // recursively check if their subtrees are mirrored. |
| 58 | + if (left != nullptr && right != nullptr && left->Value == right->Value) { |
| 59 | + return treesAreMirrored(left->Left, right->Right) && treesAreMirrored(left->Right, right->Left); |
| 60 | + } |
| 61 | + |
| 62 | + // If either left or right tree is null or their values are not equal, they are not mirrored. |
| 63 | + // Also, if both left and right trees are null, they are considered mirrored. |
| 64 | + return left == right; |
| 65 | +} |
| 66 | + |
| 67 | +// Approach 2: Iterative Approach using Stack |
| 68 | +/* |
| 69 | + In this iterative approach, we use two stacks (stackLeft and stackRight) to perform a mirror traversal of the |
| 70 | + left and right subtrees. The process is similar to the original code snippet but implemented iteratively |
| 71 | + using a while loop and stacks. The stacks are initialized with the left and right children of the root node, |
| 72 | + and in each iteration, we compare the corresponding nodes from both stacks and check for asymmetry. |
| 73 | + The children of the left and right nodes are pushed onto their respective stacks in reverse order to |
| 74 | + maintain the mirror traversal. The loop continues until both stacks are empty or an asymmetry is detected. |
| 75 | + Finally, the function returns whether the tree is symmetric or not. |
| 76 | +
|
| 77 | + The time complexity of this algorithm is O(n), where n is the number of nodes in the binary tree, as |
| 78 | + it traverses each node once. The space complexity is O(max(d, h)), where d is the maximum width of |
| 79 | + the tree (number of nodes at the widest level) and h is the height of the tree. The space complexity |
| 80 | + depends on the maximum number of nodes stored in the stacks during the traversal. |
| 81 | +
|
| 82 | +
|
| 83 | +*/ |
| 84 | +struct BinaryTree { |
| 85 | + int value; |
| 86 | + BinaryTree* left; |
| 87 | + BinaryTree* right; |
| 88 | +}; |
| 89 | + |
| 90 | +bool SymmetricalTreeIterative(BinaryTree* tree) { |
| 91 | + std::stack<BinaryTree*> stackLeft; |
| 92 | + std::stack<BinaryTree*> stackRight; |
| 93 | + stackLeft.push(tree->left); // Initialize stackLeft with the left child of the root node |
| 94 | + stackRight.push(tree->right); // Initialize stackRight with the right child of the root node |
| 95 | + |
| 96 | + // Perform mirror traversal of the left and right subtrees |
| 97 | + while (!stackLeft.empty()) { |
| 98 | + BinaryTree* left = stackLeft.top(); |
| 99 | + BinaryTree* right = stackRight.top(); |
| 100 | + stackLeft.pop(); |
| 101 | + stackRight.pop(); |
| 102 | + |
| 103 | + if (left == nullptr && right == nullptr) { |
| 104 | + continue; // Both left and right subtrees are symmetric, continue to the next iteration |
| 105 | + } |
| 106 | + |
| 107 | + if (left == nullptr || right == nullptr || left->value != right->value) { |
| 108 | + return false; // Asymmetry detected, tree is not symmetric |
| 109 | + } |
| 110 | + |
| 111 | + // Push the children of left and right onto the respective stacks in reverse order |
| 112 | + stackLeft.push(left->left); |
| 113 | + stackLeft.push(left->right); |
| 114 | + stackRight.push(right->right); |
| 115 | + stackRight.push(right->left); |
| 116 | + } |
| 117 | + |
| 118 | + return true; // Tree is symmetric |
| 119 | +} |
| 120 | + |
| 121 | + |
| 122 | +int main() { |
| 123 | + // Create a binary tree for testing |
| 124 | + BinaryTree* tree = new BinaryTree(); |
| 125 | + tree->Value = 1; |
| 126 | + tree->Left = new BinaryTree(); |
| 127 | + tree->Left->Value = 2; |
| 128 | + tree->Right = new BinaryTree(); |
| 129 | + tree->Right->Value = 2; |
| 130 | + tree->Left->Left = new BinaryTree(); |
| 131 | + tree->Left->Left->Value = 3; |
| 132 | + tree->Right->Right = new BinaryTree(); |
| 133 | + tree->Right->Right->Value = 3; |
| 134 | + |
| 135 | + // Check if the tree is symmetrical |
| 136 | + bool isSymmetrical = SymmetricalTree(tree); |
| 137 | + |
| 138 | + // Output the result |
| 139 | + if (isSymmetrical) { |
| 140 | + cout << "The binary tree is symmetrical." << endl; |
| 141 | + } else { |
| 142 | + cout << "The binary tree is not symmetrical." << endl; |
| 143 | + } |
| 144 | + |
| 145 | + // Clean up the allocated memory |
| 146 | + delete tree->Left->Left; |
| 147 | + delete tree->Right->Right; |
| 148 | + delete tree->Left; |
| 149 | + delete tree->Right; |
| 150 | + delete tree; |
| 151 | + |
| 152 | + return 0; |
| 153 | +} |
0 commit comments