diff --git a/dsa-solutions/lc-solutions/0000-0099/0083-remove-duplicates-from-sorted-list.md b/dsa-solutions/lc-solutions/0000-0099/0083-remove-duplicates-from-sorted-list.md new file mode 100644 index 000000000..ce0022bd6 --- /dev/null +++ b/dsa-solutions/lc-solutions/0000-0099/0083-remove-duplicates-from-sorted-list.md @@ -0,0 +1,121 @@ +--- +id: remove-duplicates-from-sorted-list +title: Remove Duplicates from Sorted List Solution +sidebar_label: 0083 Remove Duplicates from Sorted List +tags: + - Linked List + - Two Pointers + - LeetCode + - Python + - Java + - C++ +description: "This is a solution to the Remove Duplicates from Sorted List problem on LeetCode." +--- + +## Problem Description + +Given the head of a sorted linked list, delete all duplicates such that each element appears only once. Return the linked list sorted as well. + +### Examples + +**Example 1:** +``` +Input: head = [1,1,2] +Output: [1,2] +``` + +**Example 2:** + +``` +Input: head = [1,1,2,3,3] +Output: [1,2,3] +``` + +### Approach for Removing Duplicates from Sorted List + +**Intuition:** +The problem requires removing duplicates from a sorted singly-linked list. The approach involves iterating through the list and removing duplicates while maintaining the sorted order. + +**Approach:** +- Initialize a pointer `current` to the head of the linked list to traverse the list. +- Start a `while` loop that continues until `current` reaches the end of the list or `current.next` reaches null. +- Inside the loop, compare the value of the current node `current.val` with the value of the next node `current.next.val`. +- If the values are equal, it indicates a duplicate node. In this case, update the next pointer of the current node `current.next` to skip the next node (remove the duplicate). +- If the values are not equal, move the `current` pointer to the next node, continuing the traversal. +- Repeat the loop until the end of the list is reached, ensuring that all duplicates are removed while maintaining the sorted order of the remaining nodes. +- After the loop, return the modified linked list, which contains no duplicates. + + +### Code in Different Languages + +#### Java (code): + +```java +class Solution { + public ListNode deleteDuplicates(ListNode head) { + ListNode current = head; + + while (current != null && current.next != null) { + if (current.val == current.next.val) { + current.next = current.next.next; + } else { + current = current.next; + } + } + + return head; + } +} +``` + +#### Python (code) + +```python +class Solution: + def deleteDuplicates(self, head: ListNode) -> ListNode: + current = head + + while current and current.next: + if current.val == current.next.val: + current.next = current.next.next + else: + current = current.next + + return head +``` + +#### CPP (code) ; + +```cpp +class Solution { +public: + ListNode* deleteDuplicates(ListNode* head) { + ListNode* current = head; + + while (current && current->next) { + if (current->val == current->next->val) { + current->next = current->next->next; + } else { + current = current->next; + } + } + + return head; + } +}; +``` + +#### Complexity Analysis + +- **Time Complexity:** O(n) + + - The algorithm iterates through the linked list once, where n is the number of nodes in the list. Each node is examined once to identify and remove duplicates. + +- **Space Complexity:** O(1) + - The algorithm uses a constant amount of additional memory space for variables, regardless of the size of the input linked list, making its space complexity constant. + +## References + +- **LeetCode Problem**: [Balanced Binary Tree](https://leetcode.com/problems/balanced-binary-tree/) +- **Solution Link**: [LeetCode Solution](https://leetcode.com/problems/balanced-binary-tree/solution/) +- **Authors GeeksforGeeks Profile:** [Vipul lakum](https://leetcode.com/u/vipul_lakum_02/) \ No newline at end of file diff --git a/dsa-solutions/lc-solutions/0100-0199/0102-binary-tree-level-order-traversal.md b/dsa-solutions/lc-solutions/0100-0199/0102-binary-tree-level-order-traversal.md new file mode 100644 index 000000000..e2561902b --- /dev/null +++ b/dsa-solutions/lc-solutions/0100-0199/0102-binary-tree-level-order-traversal.md @@ -0,0 +1,520 @@ +--- +id: binary-tree-level-order-traversal +title: Binary Tree Level Order Traversal Solution +sidebar_label: 0102 Binary Tree Level Order Traversal +tags: + - Tree + - Breadth First Search + - Queue + - LeetCode + - Python + - Java + - C++ +description: "This is a solution to the Binary Tree Level Order Traversal problem on LeetCode." +--- + +## Problem Description + +Given the root of a binary tree, return the level order traversal of its nodes' values. (i.e., from left to right, level by level). + +### Examples + +**Example 1:** + +![input Tree](https://assets.leetcode.com/uploads/2021/02/19/tree1.jpg) +``` +Input: root = [3,9,20,null,null,15,7] +Output: [[3],[9,20],[15,7]] +``` + +**Example 2:** + +``` +Input: root = [1] +Output: [[1]] +``` + +**Example 3:** + +``` +Input: root = [] +Output: [] +``` + +**Constraints:** + +- The number of nodes in the tree is in the range [0, 2000]. +- $ -1000 <= $ Node.val $ <= 1000 $ + +## Solution for Binary Tree Level Order Traversal Problem + +### Intuition + +To perform a level-order traversal on a binary tree and store the nodes’ values in a 2D vector representing each level, start by initialising an empty queue to hold the level by level nodes. Enqueue the root node into the queue and traverse until the queue is empty. For each level, track the number of nodes in that level, creating a temporary vector to deque and store them. At each node, store its value in the temporary vector and enqueue its left and right children if they exist. Once all the nodes at a level are processed add this 1D temporary vector to the final 2D vector, representing that level. This process repeats until all levels are traversed. Finally, return this 2D vector containing the level order traversal of the binary tree. + +### Algorithm: + +**Step 1:** Initialise an empty queue data structure to store the nodes during traversal. Create a 2D array or a vector of a vector to store the level order traversal. If the tree is empty, return this empty 2D vector. + +**Step 2:** Enqueue the root node i.e. Add the root node of the binary tree to the queue. + +**Step 3:** + +Iterate until the queue is empty: + +- Get the current size of the queue. This size indicates the number of nodes at the current level. +- Create a vector ‘level’ to store the nodes at the current level. +- Iterate through ‘size’ number of nodes at the current level: + - Pop the front node from the queue. + - Store the node’s value in the level vector. + - Enqueue the left and right child nodes of the current node (if they exist) into the queue. +- After processing all the nodes at the current level, add the ‘level’ vector to the ‘ans’ 2D vector, representing the current level. + +**Step 4:** Once the traversal loop completes i.e. all levels have been processed, return the ‘ans’ 2D vector containing the level-order traversal. + +### Code in Different Languages + + + + + ```cpp + #include + #include + #include + + using namespace std; + + // TreeNode struct represents + // a node in a binary tree + struct TreeNode { + int val; + TreeNode* left; + TreeNode* right; + + // Default constructor for TreeNode + TreeNode() : val(0), left(nullptr), right(nullptr) {} + + // Constructor with a value + // parameter for TreeNode + TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + + // Constructor with value, left + // child, and right child + // parameters for TreeNode + TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {} + }; + + + class Solution { + public: + // Function to perform level-order + // traversal of a binary tree + vector> levelOrder(TreeNode* root) { + // Create a 2D vector to store levels + vector> ans; + if (root == nullptr) { + // If the tree is empty, + // return an empty vector + return ans; + } + + // Create a queue to store nodes + // for level-order traversal + queue q; + // Push the root node to the queue + q.push(root); + + while (!q.empty()) { + // Get the size of the current level + int size = q.size(); + // Create a vector to store + // nodes at the current level + vector level; + + for (int i = 0; i < size; i++) { + // Get the front node in the queue + TreeNode* node = q.front(); + // Remove the front node from the queue + q.pop(); + // Store the node value + // in the current level vector + level.push_back(node->val); + + // Enqueue the child nodes if they exist + if (node->left != nullptr) { + q.push(node->left); + } + if (node->right != nullptr) { + q.push(node->right); + } + } + // Store the current level + // in the answer vector + ans.push_back(level); + } + // Return the level-order + // traversal of the tree + return ans; + } + }; + + // Function to print + // the elements of a vector + void printVector(const vector& vec) { + // Iterate through the + // vector and print each element + for (int num : vec) { + cout << num << " "; + } + cout << endl; + } + + // Main function + int main() { + // Creating a sample binary tree + TreeNode* root = new TreeNode(1); + root->left = new TreeNode(2); + root->right = new TreeNode(3); + root->left->left = new TreeNode(4); + root->left->right = new TreeNode(5); + + // Create an instance + // of the Solution class + Solution solution; + // Perform level-order traversal + vector> result = solution.levelOrder(root); + + cout << "Level Order Traversal of Tree: "<< endl; + + // Printing the level order traversal result + for (const vector& level : result) { + printVector(level); + } + + return 0; + } + ``` + + + + + + ``` + #include + #include + #include + + using namespace std; + + // TreeNode struct represents + // a node in a binary tree + struct TreeNode { + int val; + TreeNode* left; + TreeNode* right; + + // Default constructor for TreeNode + TreeNode() : val(0), left(nullptr), right(nullptr) {} + + // Constructor with a value + // parameter for TreeNode + TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + + // Constructor with value, left + // child, and right child + // parameters for TreeNode + TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {} + }; + + + class Solution { + public: + // Function to perform level-order + // traversal of a binary tree + vector> levelOrder(TreeNode* root) { + // Create a 2D vector to store levels + vector> ans; + if (root == nullptr) { + // If the tree is empty, + // return an empty vector + return ans; + } + + // Create a queue to store nodes + // for level-order traversal + queue q; + // Push the root node to the queue + q.push(root); + + while (!q.empty()) { + // Get the size of the current level + int size = q.size(); + // Create a vector to store + // nodes at the current level + vector level; + + for (int i = 0; i < size; i++) { + // Get the front node in the queue + TreeNode* node = q.front(); + // Remove the front node from the queue + q.pop(); + // Store the node value + // in the current level vector + level.push_back(node->val); + + // Enqueue the child nodes if they exist + if (node->left != nullptr) { + q.push(node->left); + } + if (node->right != nullptr) { + q.push(node->right); + } + } + // Store the current level + // in the answer vector + ans.push_back(level); + } + // Return the level-order + // traversal of the tree + return ans; + } + }; + + // Function to print + // the elements of a vector + void printVector(const vector& vec) { + // Iterate through the + // vector and print each element + for (int num : vec) { + cout << num << " "; + } + cout << endl; + } + + // Main function + int main() { + // Creating a sample binary tree + TreeNode* root = new TreeNode(1); + root->left = new TreeNode(2); + root->right = new TreeNode(3); + root->left->left = new TreeNode(4); + root->left->right = new TreeNode(5); + + // Create an instance + // of the Solution class + Solution solution; + // Perform level-order traversal + vector> result = solution.levelOrder(root); + + cout << "Level Order Traversal of Tree: "<< endl; + + // Printing the level order traversal result + for (const vector& level : result) { + printVector(level); + } + + return 0; + } + ``` + + + + + + ``` + from collections import deque + + # TreeNode class represents + # a node in a binary tree + class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + + class Solution: + def levelOrder(self, root): + # Create a list to store levels + ans = [] + if not root: + # If the tree is empty, + # return an empty list + return ans + + # Create a queue to store nodes + # for level-order traversal + q = deque() + # Enqueue the root node + q.append(root) + + while q: + # Get the size of the current level + size = len(q) + # Create a list to store + # nodes at the current level + level = [] + + for i in range(size): + # Get the front node in the queue + node = q.popleft() + # Store the node value + # in the current level list + level.append(node.val) + + # Enqueue the child nodes if they exist + if node.left: + q.append(node.left) + if node.right: + q.append(node.right) + + # Store the current level + # in the answer list + ans.append(level) + # Return the level-order + # traversal of the tree + return ans + + # Function to print + # the elements of a list + def printList(lst): + # Iterate through the + # list and print each element + for num in lst: + print(num, end=" ") + print() + + # Main function + if __name__ == "__main__": + # Creating a sample binary tree + root = TreeNode(1) + root.left = TreeNode(2) + root.right = TreeNode(3) + root.left.left = TreeNode(4) + root.left.right = TreeNode(5) + + # Create an instance + # of the Solution class + solution = Solution() + # Perform level-order traversal + result = solution.levelOrder(root) + + print("Level Order Traversal of Tree:") + + # Printing the level order traversal result + for level in result: + printList(level) + ``` + + + + + + ```javascript + // TreeNode class represents + // a node in a binary tree + class TreeNode { + constructor(val = 0, left = null, right = null) { + this.val = val; + this.left = left; + this.right = right; + } + } + + class Solution { + // Function to perform level-order + // traversal of a binary tree + levelOrder(root) { + // Create an array to store levels + let ans = []; + if (!root) { + // If the tree is empty, + // return an empty array + return ans; + } + + // Create a queue to store + // nodes for level-order traversal + let q = []; + // Push the root node to the queue + q.push(root); + + while (q.length > 0) { + // Get the size of the current level + let size = q.length; + // Create an array to store + // nodes at the current level + let level = []; + + for (let i = 0; i < size; i++) { + // Get the front node in the queue + let node = q.shift(); + // Store the node value + // in the current level array + level.push(node.val); + + // Enqueue the child + // nodes if they exist + if (node.left !== null) { + q.push(node.left); + } + if (node.right !== null) { + q.push(node.right); + } + } + // Store the current level + // in the answer array + ans.push(level); + } + // Return the level-order + // traversal of the tree + return ans; + } + } + + // Function to print the + // elements of an array + function printArray(arr) { + // Iterate through the + // array and print each element + for (let num of arr) { + console.log(num + " "); + } + console.log("\n"); + } + + // Creating a sample binary tree + let root = new TreeNode(1); + root.left = new TreeNode(2); + root.right = new TreeNode(3); + root.left.left = new TreeNode(4); + root.left.right = new TreeNode(5); + + // Create an instance of the Solution class + let solution = new Solution(); + // Perform level-order traversal + let result = solution.levelOrder(root); + + console.log("Level Order Traversal of Tree: \n"); + + // Printing the level order traversal result + for (let level of result) { + printArray(level); + } + ``` + + + + +#### Complexity Analysis + +- **Time Complexity:** O(N) where N is the number of nodes in the binary tree. Each node of the binary tree is enqueued and dequeued exactly once, hence all nodes need to be processed and visited. Processing each node takes constant time operations which contributes to the overall linear time complexity. + +- **Space Complexity:** O(N) where N is the number of nodes in the binary tree. In the worst case, the queue has to hold all the nodes of the last level of the binary tree, the last level could at most hold N/2 nodes hence the space complexity of the queue is proportional to O(N). The resultant vector answer also stores the values of the nodes level by level and hence contains all the nodes of the tree contributing to O(N) space as well. + +--- + +## References + +- **LeetCode Problem:** [Symmetric Tree Problem](https://leetcode.com/problems/symmetric-tree/) +- **Solution Link:** [Symmetric Tree Solution on LeetCode](https://leetcode.com/problems/symmetric-tree/solutions/5016750/easy-recursion-solution-in-c-100-beats-full-expanation-with-example/) +- **Authors GeeksforGeeks Profile:** [Vipul lakum](https://leetcode.com/u/vipul_lakum_02/) diff --git a/dsa-solutions/lc-solutions/0100-0199/0104-maximum-depth-of-binary-tree.md b/dsa-solutions/lc-solutions/0100-0199/0104-maximum-depth-of-binary-tree.md index 331604352..50ca3528e 100644 --- a/dsa-solutions/lc-solutions/0100-0199/0104-maximum-depth-of-binary-tree.md +++ b/dsa-solutions/lc-solutions/0100-0199/0104-maximum-depth-of-binary-tree.md @@ -45,7 +45,6 @@ Output: 2 ## Solution for Maximum Depth of Binary Tree Problem - @@ -62,9 +61,83 @@ To find the maximum depth of a binary tree, we can use a depth-first search (DFS 3. Recursively find the maximum depth of the left and right subtrees. 4. Return the maximum of the left and right subtree depths plus one. +#### Implementation + +```jsx live +function MaxDepthOfBinaryTree() { + class TreeNode { + constructor(val = 0, left = null, right = null) { + this.val = val; + this.left = left; + this.right = right; + } + } + + const maxDepth = function (root) { + if (!root) return 0; + const leftDepth = maxDepth(root.left); + const rightDepth = maxDepth(root.right); + return Math.max(leftDepth, rightDepth) + 1; + }; + + const root = new TreeNode(3); + root.left = new TreeNode(9); + root.right = new TreeNode(20); + root.right.left = new TreeNode(15); + root.right.right = new TreeNode(7); + + const result = maxDepth(root); + return ( +
+

+ Input: root = [3,9,20,null,null,15,7] +

+

+ Output: {result} +

+
+ ); +} +``` + #### Code in Different Languages + + + ```javascript + function maxDepth(root) { + if (!root) return 0; + const maxLeft = maxDepth(root.left); + const maxRight = maxDepth(root.right); + return Math.max(maxLeft, maxRight) + 1; + } + ``` + + + + + ```typescript + class TreeNode { + val: number; + left: TreeNode | null; + right: TreeNode | null; + constructor(val: number) { + this.val = val; + this.left = null; + this.right = null; + } + } + + function maxDepth(root: TreeNode | null): number { + if (!root) return 0; + const maxLeft: number = maxDepth(root.left); + const maxRight: number = maxDepth(root.right); + return Math.max(maxLeft, maxRight) + 1; + } + ``` + + ```java @@ -128,9 +201,120 @@ Another approach to find the maximum depth of a binary tree is to use breadth-fi - Push all the children of the current level into the queue. 4. Return `depth` after traversing all levels. +#### Implementation + +```jsx live +function MaxDepthOfBinaryTree() { + class TreeNode { + constructor(val) { + this.val = val; + this.left = null; + this.right = null; + } + } + + // Creating the binary tree + const root = new TreeNode(3); + root.left = new TreeNode(9); + root.right = new TreeNode(20); + root.right.left = new TreeNode(15); + root.right.right = new TreeNode(7); + + const maxDepth = function (root) { + if (!root) return 0; + + let depth = 0; + const queue = [root]; + + while (queue.length) { + const size = queue.length; + for (let i = 0; i < size; i++) { + const node = queue.shift(); + if (node.left) queue.push(node.left); + if (node.right) queue.push(node.right); + } + depth++; + } + + return depth; + }; + + const result = maxDepth(root); + return ( +
+

+ Binary Tree: {JSON.stringify(root)} +

+

+ Maximum Depth: {result} +

+
+ ); +} +``` + #### Code in Different Languages + + + ```javascript + function maxDepth(root) { + if (!root) return 0; + + let depth = 0; + const queue = [root]; + + while (queue.length) { + depth++; + const levelSize = queue.length; + for (let i = 0; i < levelSize; ++i) { + const node = queue.shift(); + if (node.left) queue.push(node.left); + if (node.right) queue.push(node.right); + } + } + + return depth; + } + ``` + + + + + ```typescript + class TreeNode { + val: number; + left: TreeNode | null; + right: TreeNode | null; + constructor(val: number) { + this.val = val; + this.left = null; + this.right = null; + } + } + + function maxDepth(root: TreeNode | null): number { + if (!root) return 0; + + let depth = 0; + const queue: TreeNode[] = [root]; + + while (queue.length) { + depth++; + const levelSize = queue.length; + for (let i = 0; i < levelSize; ++i) { + const node = queue.shift()!; + if (node.left) queue.push(node.left); + if (node.right) queue.push(node.right); + } + } + + return depth; + } + ``` + + ```java @@ -220,4 +404,5 @@ Another approach to find the maximum depth of a binary tree is to use breadth-fi - **LeetCode Problem**: [Maximum Depth of Binary Tree](https://leetcode.com/problems/maximum-depth-of-binary-tree/) - **Solution Link**: [LeetCode Solution](https://leetcode.com/problems/maximum-depth-of-binary-tree/solution/) - **Authors GeeksforGeeks Profile:** [Vipul lakum](https://leetcode.com/u/vipul_lakum_02/) ---- \ No newline at end of file + +--- diff --git a/dsa-solutions/lc-solutions/0100-0199/0110-balanced-binary-tree.md b/dsa-solutions/lc-solutions/0100-0199/0110-balanced-binary-tree.md new file mode 100644 index 000000000..7556e0245 --- /dev/null +++ b/dsa-solutions/lc-solutions/0100-0199/0110-balanced-binary-tree.md @@ -0,0 +1,256 @@ +--- +id: balanced-binary-tree +title: Balanced Binary Tree Solution +sidebar_label: 0110 Balanced Binary Tree +tags: + - Binary Tree + - Depth-First Search + - Recursion + - LeetCode + - C++ + - Java + - Python +description: "This is a solution to the Balanced Binary Tree problem on LeetCode." +--- + +## Problem Description + +Given a binary tree, determine if it is height-balanced. + +A height-balanced binary tree is defined as: + +- A binary tree in which the left and right subtrees of every node differ in height by no more than 1. + +### Examples + +**Example 1:** + +![input Tree](https://assets.leetcode.com/uploads/2020/10/06/balance_1.jpg) + +``` +Input: root = [3,9,20,null,null,15,7] +Output: true +``` + +**Example 2:** + +![input Tree](https://assets.leetcode.com/uploads/2020/10/06/balance_2.jpg) +``` +Input: root = [1,2,2,3,3,null,null,4,4] +Output: false +``` + +**Example 3:** + +``` +Input: root = [] +Output: true +``` + +### Constraints + +- The number of nodes in the tree is in the range `[0, 5000]`. +- $ -10^4 <=$ Node.val $<= 10^4 $ + +--- + +## Solution for Balanced Binary Tree Problem + + + + +### Approach 1: Top-Down + +#### Intuition + +This method checks whether the tree is balanced strictly according to the definition of a balanced binary tree: the difference between the heights of the two subtrees is not greater than 1, and both the left and right subtrees are also balanced. With the helper function depth(), we can easily write the code. + +#### Implementation + +Implement a helper function `depth(root)` that returns the depth of the tree rooted at root. +Check if the absolute difference between the depths of the left and right subtrees is not greater than 1. +Recursively check if both the left and right subtrees are balanced. +Return true if the tree is balanced, otherwise return false. + +#### Code in Different Languages + + + + + ```java + class Solution { + public int depth(TreeNode root) { + if (root == null) return 0; + return Math.max(depth(root.left), depth(root.right)) + 1; + } + + public boolean isBalanced(TreeNode root) { + if (root == null) return true; + + int left = depth(root.left); + int right = depth(root.right); + + return Math.abs(left - right) <= 1 && isBalanced(root.left) && isBalanced(root.right); + } + } + ``` + + + + + ```python + class Solution: + def depth(self, root: TreeNode) -> int: + if root is None: + return 0 + return max(self.depth(root.left), self.depth(root.right)) + 1 + + def isBalanced(self, root: TreeNode) -> bool: + if root is None: + return True + + left = self.depth(root.left) + right = self.depth(root.right) + + return abs(left - right) <= 1 and self.isBalanced(root.left) and self.isBalanced(root.right) + ``` + + + + + ```cpp + class Solution { + public: + int depth(TreeNode* root) { + if (root == nullptr) return 0; + return max(depth(root->left), depth(root->right)) + 1; + } + + bool isBalanced(TreeNode* root) { + if (root == nullptr) return true; + + int left = depth(root->left); + int right = depth(root->right); + + return abs(left - right) <= 1 && isBalanced(root->left) && isBalanced(root->right); + } + }; + ``` + + + + +#### Complexity Analysis + +- **Time Complexity**: O(n log n) in the worst case where n is the number of nodes in the tree. We visit each node once, and for each node, we calculate its depth. Since the depth calculation involves traversing the subtree, the overall time complexity is O(n log n). +- **Space Complexity**: O(n) for the recursive call stack. + + + + +### Approach 2: Bottom-Up + +#### Intuition + +The second method is based on DFS. Instead of calling depth() explicitly for each child node, we return the height of the current node in DFS recursion. When the subtree of the current node (inclusive) is balanced, the function dfsHeight() returns a non-negative value as the height. Otherwise, -1 is returned. According to the left height and right height of the two children, the parent node could check if the subtree is balanced and decide its return value. + +#### Implementation + +Implement a helper function dfsHeight(root) that returns the height of the tree rooted at root. +If the subtree rooted at root is balanced, return its height. Otherwise, return -1. +Check if the returned height is -1 to determine if the tree is balanced. + +#### Code in Different Languages + + + + + ```java + class Solution { + public int dfsHeight(TreeNode root) { + if (root == null) return 0; + + int leftHeight = dfsHeight(root.left); + if (leftHeight == -1) return -1; + int rightHeight = dfsHeight(root.right); + if (rightHeight == -1) return -1; + + if (Math.abs(leftHeight - rightHeight) > 1) return -1; + return Math.max(leftHeight, rightHeight) + 1; + } + + public boolean isBalanced(TreeNode root) { + return dfsHeight(root) != -1; + } + } + ``` + + + + + ```python + class Solution: + def dfsHeight(self, root: TreeNode) -> int: + if root is None: + return 0 + + leftHeight = self.dfsHeight(root.left) + if leftHeight == -1: + return -1 + right + + Height = self.dfsHeight(root.right) + if rightHeight == -1: + return -1 + + if abs(leftHeight - rightHeight) > 1: + return -1 + return max(leftHeight, rightHeight) + 1 + + def isBalanced(self, root: TreeNode) -> bool: + return self.dfsHeight(root) != -1 + ``` + + + + + ```cpp + class Solution { + public: + int dfsHeight(TreeNode* root) { + if (root == nullptr) return 0; + + int leftHeight = dfsHeight(root->left); + if (leftHeight == -1) return -1; + int rightHeight = dfsHeight(root->right); + if (rightHeight == -1) return -1; + + if (abs(leftHeight - rightHeight) > 1) return -1; + return max(leftHeight, rightHeight) + 1; + } + + bool isBalanced(TreeNode* root) { + return dfsHeight(root) != -1; + } + }; + ``` + + + + +#### Complexity Analysis + +- **Time Complexity**: O(n) in the worst case where n is the number of nodes in the tree. Each node is visited once. +- **Space Complexity**: O(n) for the recursive call stack. + + + + +## References + +- **LeetCode Problem**: [Balanced Binary Tree](https://leetcode.com/problems/balanced-binary-tree/) +- **Solution Link**: [LeetCode Solution](https://leetcode.com/problems/balanced-binary-tree/solution/) +- **Authors GeeksforGeeks Profile:** [Vipul lakum](https://leetcode.com/u/vipul_lakum_02/) + + +--- diff --git a/dsa-solutions/lc-solutions/0100-0199/0125-valid-palindrome.md b/dsa-solutions/lc-solutions/0100-0199/0125-valid-palindrome.md new file mode 100644 index 000000000..466830035 --- /dev/null +++ b/dsa-solutions/lc-solutions/0100-0199/0125-valid-palindrome.md @@ -0,0 +1,339 @@ +--- +id: valid-palindrome +title: Valid Palindrome Solution +sidebar_label: 0125 Valid Palindrome +tags: + - String + - Two Pointer + - LeetCode + - Python + - Java + - C++ +description: "This is a solution to the Valid Palindrome problem on LeetCode." +--- + +## Problem Description + +Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases. + +### Examples + +**Example 1:** + +``` +Input: "A man, a plan, a canal: Panama" +Output: true +Explanation: "amanaplanacanalpanama" is a palindrome. +``` + +**Example 2:** + +``` +Input: "race a car" +Output: false +Explanation: "raceacar" is not a palindrome. +``` + +### Constraints + +- The input string may consist of uppercase and lowercase letters, digits, and punctuation symbols. +- The empty string is considered a valid palindrome. + +## Solution for Valid Palindrome Problem + + + + +### Approach 1: Brute Force + +#### Intuition + +The brute force approach involves stripping non-alphanumeric characters from the string and then checking if the resulting string is a palindrome by comparing it with its reverse. + +#### Implementation + +```jsx live +function ValidPalindromeTwoPointer() { + const isPalindrome = function (s) { + if (!s) return true; + let left = 0, + right = s.length - 1; + while (left < right) { + while (left < right && !s[left].match(/[a-zA-Z0-9]/)) left++; + while (left < right && !s[right].match(/[a-zA-Z0-9]/)) right--; + if (s[left].toLowerCase() !== s[right].toLowerCase()) return false; + left++; + right--; + } + return true; + }; + + const input = "A man, a plan, a canal: Panama"; + const output = isPalindrome(input); + + return ( +
+

+ Input: {input} +

+

+ Output: {output.toString()} +

+
+ ); +} +``` + +#### Code in Different Languages + + + + + ```javascript + function isPalindrome(s) { + if (!s) return true; + const cleanedS = s.replace(/[^A-Za-z0-9]/g, '').toLowerCase(); + return cleanedS === cleanedS.split('').reverse().join(''); + } + ``` + + + + + ```typescript + function isPalindrome(s: string): boolean { + if (!s) return true; + const cleanedS = s.replace(/[^A-Za-z0-9]/g, '').toLowerCase(); + return cleanedS === cleanedS.split('').reverse().join(''); + } + + const input: string = "A man, a plan, a canal: Panama"; + const output: boolean = isPalindrome(input); + + console.log("Input:", input); + console.log("Output:", output); + ``` + + + + + ```python + def is_palindrome(s: str) -> bool: + if not s: + return True + cleaned_s = ''.join(ch.lower() for ch in s if ch.isalnum()) + return cleaned_s == cleaned_s[::-1] + + input_str = "A man, a plan, a canal: Panama" + output = is_palindrome(input_str) + + print("Input:", input_str) + print("Output:", output) + + ``` + + + + + ```java + class Solution { + public boolean isPalindrome(String s) { + if (s == null || s.isEmpty()) { + return true; + } + + String cleanedS = s.replaceAll("[^A-Za-z0-9]", "").toLowerCase(); + return cleanedS.equals(new StringBuilder(cleanedS).reverse().toString()); + } + } + ``` + + + + + ```cpp + class Solution { + public: + bool isPalindrome(string s) { + if (s.empty()) { + return true; + } + + string cleanedS; + for (char ch : s) { + if (isalnum(ch)) { + cleanedS += tolower(ch); + } + } + + string reversedS = cleanedS; + reverse(reversedS.begin(), reversedS.end()); + + return cleanedS == reversedS; + } + }; + ``` + + + + +#### Complexity Analysis + +- Time Complexity: O(n), where n is the length of the input string. We iterate through the string once. +- Space Complexity: O(n), where n is the length of the input string. We create a new string to store the cleaned version of the input. + +
+ + +### Approach 2: Two Pointer + +#### Intuition + +The two-pointer approach involves using two pointers, one starting from the beginning of the string and the other starting from the end. We move both pointers towards the center of the string, comparing characters at each step until they meet or cross each other. + +#### Implementation + +```jsx live +function ValidPalindromeBruteForce() { + const isPalindrome = function (s) { + if (!s) return true; + const cleanedS = s.replace(/[^A-Za-z0-9]/g, "").toLowerCase(); + return cleanedS === cleanedS.split("").reverse().join(""); + }; + + const input = "A man, a plan, a canal: Panama"; + const output = isPalindrome(input); + + return ( +
+

+ Input: {input} +

+

+ Output: {output.toString()} +

+
+ ); +} +``` + +#### Code in Different Languages + + + + + ```javascript + function isPalindrome(s) { + if (!s) return true; + let left = 0, right = s.length - 1; + while (left < right) { + while (left < right && !s[left].match(/[a-zA-Z0-9]/)) left++; + while (left < right && !s[right].match(/[a-zA-Z0-9]/)) right--; + if (s[left].toLowerCase() !== s[right].toLowerCase()) return false; + left++; + right--; + } + return true; + } + ``` + + + + + ```typescript + function isPalindrome(s: string): boolean { + if (!s) return true; + let left = 0, right = s.length - 1; + while (left < right) { + while (left < right && !s[left].match(/[a-zA-Z0-9]/)) left++; + while (left < right && !s[right].match(/[a-zA-Z0-9]/)) right--; + if (s[left].toLowerCase() !== s[right].toLowerCase()) return false; + left++; + right--; + } + return true; + } + ``` + + + + + ```java + class Solution { + public boolean isPalindrome(String s) { + if (s == null || s.isEmpty()) { + return true; + } + + int left = 0, right = s.length() - 1; + while (left < right) { + while (left < right && !Character.isLetterOrDigit(s.charAt(left))) left++; + while (left < right && !Character.isLetterOrDigit(s.charAt(right))) right--; + if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) return false; + left++; + right--; + } + return true; + } + } + ``` + + + + + ```python + def is_palindrome(s: str) -> bool: + if not s: + return True + left, right = 0, len(s) - 1 + while left < right: + while left < right and not s[left].isalnum(): left += 1 + while left < right and not s[right].isalnum(): right -= 1 + if s[left].lower() != s[right].lower(): return False + left += 1 + right -= 1 + return True + ``` + + + + + ```cpp + class Solution { + public: + bool isPalindrome(string s) { + if (s.empty()) { + return true; + } + + int left = 0, right = s.length() - 1; + while (left < right) { + while (left < right && !isalnum(s[left])) left++; + while (left < right && !isalnum(s[right])) right--; + if (tolower(s[left]) != tolower(s[right])) return false; + left++; + right--; + } + return true; + } + }; + ``` + + + + +#### Complexity Analysis + +- Time Complexity: O(n), where n is the length of the input string. We iterate through the string once. +- Space Complexity: O(1). We're not using any extra space. + +
+
+ +## References + +- **LeetCode Problem**: [Valid Palindrome](https://leetcode.com/problems/valid-palindrome/) + +- **Solution Link**: [LeetCode Solution](https://leetcode.com/problems/valid-palindrome/solution/) + +- **Authors GeeksforGeeks Profile:** [Vipul lakum](https://leetcode.com/u/vipul_lakum_02/)