├── LICENSE ├── Numpy ├── Easy │ ├── array_sum.md │ ├── array_indexing.md │ ├── element_wise_multiplication.md │ └── array_reshape.md ├── Medium │ ├── array_sorting.md │ └── array_broadcasting.md └── Hard │ ├── fourier_transform.md │ └── eigenvalue_computation.md ├── JavaScript ├── Dynamic_Programming │ ├── Easy │ │ ├── fibonacci_number.md │ │ ├── climbing_stairs.md │ │ ├── min_cost_climbing_stairs.md │ │ └── house_robber.md │ ├── Medium │ │ ├── unique_paths.md │ │ └── longest_increasing_subsequence.md │ └── Hard │ │ └── longest_valid_parentheses.md ├── Sorting_Searching │ ├── Medium │ │ ├── kth_largest_element.md │ │ ├── sort_colors.md │ │ └── top_k_frequent_elements.md │ ├── Easy │ │ ├── valid_anagram.md │ │ └── merge_sorted_array.md │ └── Hard │ │ └── find_minimum_in_rotated_sorted_array_ii.markdown ├── Linked_Lists │ ├── Easy │ │ ├── middle_of_linked_list.md │ │ └── reverse_linked_list.md │ └── Medium │ │ ├── swap_nodes_in_pairs.md │ │ └── remove_nth_node.md ├── Trees │ └── Easy │ │ ├── maximum_depth_of_binary_tree.md │ │ ├── same_tree.md │ │ ├── binary_tree_inorder_traversal.md │ │ └── symmetric_tree.md ├── Arrays │ ├── Medium │ │ ├── rotate_array.md │ │ └── container_with_most_water.md │ ├── Easy │ │ ├── move_zeroes.md │ │ ├── contains_duplicate.md │ │ ├── single_number.md │ │ └── majority_element.md │ └── Hard │ │ ├── first_missing_positive.md │ │ └── maximum_subarray_product.md └── Backtracking │ ├── Easy │ ├── Easy_subsets.md │ └── combinations.md │ └── Medium │ └── subsets_ii.md ├── Java ├── Dynamic_Programming │ └── Easy │ │ ├── fibonacci_number.md │ │ ├── climbing_stairs.md │ │ └── min_cost_climbing_stairs.md ├── Trees │ └── Easy │ │ ├── maximum_depth_of_binary_tree.md │ │ ├── same_tree.md │ │ ├── symmetric_tree.md │ │ └── binary_tree_inorder_traversal.md ├── Sorting_Searching │ ├── Medium │ │ └── kth_largest_element.md │ └── Easy │ │ └── valid_anagram.md ├── Linked_Lists │ ├── Easy │ │ ├── middle_of_linked_list.md │ │ └── reverse_linked_list.md │ └── Medium │ │ └── swap_nodes_in_pairs.md └── Arrays │ ├── Easy │ ├── move_zeroes.md │ ├── single_number.md │ └── majority_element.md │ ├── Medium │ └── rotate_array.md │ └── Hard │ └── first_missing_positive.md ├── Python ├── Dynamic_Programming │ └── Easy │ │ ├── fibonacci_number.md │ │ ├── climbing_stairs.md │ │ └── min_cost_climbing_stairs.md ├── Sorting_Searching │ ├── Medium │ │ ├── kth_largest_element.md │ │ ├── sort_colors.md │ │ └── top_k_frequent_elements.md │ ├── Easy │ │ ├── valid_anagram.md │ │ └── merge_sorted_array.md │ └── Hard │ │ └── find_minimum_in_rotated_sorted_array_ii.markdown ├── Linked_Lists │ ├── Easy │ │ ├── middle_of_linked_list.md │ │ ├── reverse_linked_list.md │ │ └── linked_list_cycle.md │ └── Medium │ │ ├── swap_nodes_in_pairs.md │ │ └── remove_nth_node.md ├── Arrays │ ├── Medium │ │ ├── rotate_array.md │ │ ├── container_with_most_water.md │ │ └── group_anagrams.md │ ├── Hard │ │ ├── first_missing_positive.md │ │ ├── maximum_subarray_product.md │ │ └── trapping_rain_water.md │ └── Easy │ │ ├── move_zeroes.md │ │ ├── contains_duplicate.md │ │ ├── single_number.md │ │ └── majority_element.md ├── Trees │ └── Easy │ │ ├── maximum_depth_of_binary_tree.md │ │ ├── same_tree.md │ │ ├── binary_tree_inorder_traversal.md │ │ └── symmetric_tree.md ├── Backtracking │ ├── Easy │ │ ├── combinations.md │ │ ├── Easy_subsets.md │ │ └── generate_parentheses.md │ └── Medium │ │ ├── subsets_ii.md │ │ └── permutations.md └── Stacks_Queues │ ├── Hard │ └── sliding_window_maximum.md │ ├── Easy │ └── valid_parentheses.md │ └── Medium │ └── daily_temperatures.md ├── MySQL ├── Easy │ ├── duplicate_emails.md │ └── second_highest_salary.md └── Hard │ └── shortest_distance_in_a_line.md └── Pandas └── Easy ├── invalid_tweets.md └── recyclable_and_low_fat_products.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 rohanmistry231 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Numpy/Easy/array_sum.md: -------------------------------------------------------------------------------- 1 | # Array Sum 2 | 3 | ## Problem Statement 4 | Write a NumPy program to compute the sum of all elements in a 1D array. 5 | 6 | **Input**: 7 | - `arr`: 1D array of numbers (e.g., `[1, 2, 3, 4]`) 8 | 9 | **Output**: 10 | - Sum of all elements (e.g., `10`) 11 | 12 | **Constraints**: 13 | - `1 <= len(arr) <= 10^5` 14 | - `-10^5 <= arr[i] <= 10^5` 15 | 16 | ## Solution 17 | ```python 18 | import numpy as np 19 | 20 | def array_sum(arr: list) -> float: 21 | # Convert to numpy array and compute sum 22 | return np.sum(arr) 23 | ``` 24 | 25 | ## Reasoning 26 | - **Approach**: Convert input list to NumPy array implicitly via `np.sum`. Use NumPy’s `sum` function to compute the total. Return the result. 27 | - **Why np.sum?**: Optimized for fast array summation using vectorized operations. 28 | - **Edge Cases**: 29 | - Empty array: `np.sum` returns 0 (handled by constraints). 30 | - Single element: Returns the element itself. 31 | - Large values: NumPy handles overflow with float64. 32 | - **Optimizations**: `np.sum` is highly optimized, avoiding Python loops. 33 | 34 | ## Performance Analysis 35 | - **Time Complexity**: O(n), where n is the array length, for summing elements. 36 | - **Space Complexity**: O(1), as no additional storage is needed beyond input. 37 | - **NumPy Efficiency**: Uses C-based vectorized operations for fast summation. 38 | 39 | ## Best Practices 40 | - Use `np.sum` for array summation. 41 | - Avoid Python loops for better performance. 42 | - Follow PEP 8 for Python code style. 43 | 44 | ## Alternative Approaches 45 | - **Python Sum**: Use built-in `sum` (O(n), slower). 46 | ```python 47 | def array_sum(arr: list) -> float: 48 | return sum(arr) 49 | ``` 50 | - **Manual Loop**: Sum elements manually (O(n), least efficient). 51 | ```python 52 | def array_sum(arr: list) -> float: 53 | total = 0 54 | for x in arr: 55 | total += x 56 | return total 57 | ``` -------------------------------------------------------------------------------- /JavaScript/Dynamic_Programming/Easy/fibonacci_number.md: -------------------------------------------------------------------------------- 1 | # Fibonacci Number 2 | 3 | ## Problem Statement 4 | The Fibonacci numbers are defined as: `F(0) = 0`, `F(1) = 1`, and `F(n) = F(n-1) + F(n-2)` for `n > 1`. Given `n`, return the value of `F(n)`. 5 | 6 | **Example**: 7 | - Input: `n = 2` 8 | - Output: `1` 9 | - Explanation: `F(2) = F(1) + F(0) = 1 + 0 = 1`. 10 | 11 | **Constraints**: 12 | - `0 <= n <= 30` 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | function fib(n) { 19 | if (n <= 1) return n; 20 | const dp = new Array(n + 1).fill(0); 21 | dp[1] = 1; 22 | for (let i = 2; i <= n; i++) { 23 | dp[i] = dp[i - 1] + dp[i - 2]; 24 | } 25 | return dp[n]; 26 | } 27 | ``` 28 | 29 | ## Reasoning 30 | - **Approach**: Use dynamic programming to compute the nth Fibonacci number. Each number is the sum of the previous two: `dp[i] = dp[i-1] + dp[i-2]`. Initialize `dp[0] = 0`, `dp[1] = 1`. 31 | - **Why DP?**: Avoids exponential recursive calls by storing intermediate results. 32 | - **Edge Cases**: 33 | - `n = 0`: Return 0. 34 | - `n = 1`: Return 1. 35 | - **Optimizations**: Use array-based DP; can optimize to O(1) space with two variables. 36 | 37 | ## Complexity Analysis 38 | - **Time Complexity**: O(n), single loop from 2 to n. 39 | - **Space Complexity**: O(n) for the DP array. Can be optimized to O(1) using two variables. 40 | 41 | ## Best Practices 42 | - Use clear variable names (e.g., `dp` for dynamic programming array). 43 | - For Python, use type hints for clarity. 44 | - For JavaScript, use array initialization with `fill`. 45 | - For Java, follow Google Java Style Guide. 46 | - Handle base cases early to avoid unnecessary computation. 47 | 48 | ## Alternative Approaches 49 | - **Optimized Space DP**: Use two variables (O(n) time, O(1) space). 50 | - **Recursion with Memoization**: Cache results (O(n) time, O(n) space). Less efficient than iterative. 51 | - **Matrix Exponentiation**: Compute Fibonacci using matrix (O(log n) time). Overkill for small n. -------------------------------------------------------------------------------- /Java/Dynamic_Programming/Easy/fibonacci_number.md: -------------------------------------------------------------------------------- 1 | # Fibonacci Number 2 | 3 | ## Problem Statement 4 | The Fibonacci numbers are defined as: `F(0) = 0`, `F(1) = 1`, and `F(n) = F(n-1) + F(n-2)` for `n > 1`. Given `n`, return the value of `F(n)`. 5 | 6 | **Example**: 7 | - Input: `n = 2` 8 | - Output: `1` 9 | - Explanation: `F(2) = F(1) + F(0) = 1 + 0 = 1`. 10 | 11 | **Constraints**: 12 | - `0 <= n <= 30` 13 | 14 | ## Solution 15 | 16 | ### Java 17 | ```java 18 | class Solution { 19 | public int fib(int n) { 20 | if (n <= 1) return n; 21 | int[] dp = new int[n + 1]; 22 | dp[1] = 1; 23 | for (int i = 2; i <= n; i++) { 24 | dp[i] = dp[i - 1] + dp[i - 2]; 25 | } 26 | return dp[n]; 27 | } 28 | } 29 | ``` 30 | 31 | ## Reasoning 32 | - **Approach**: Use dynamic programming to compute the nth Fibonacci number. Each number is the sum of the previous two: `dp[i] = dp[i-1] + dp[i-2]`. Initialize `dp[0] = 0`, `dp[1] = 1`. 33 | - **Why DP?**: Avoids exponential recursive calls by storing intermediate results. 34 | - **Edge Cases**: 35 | - `n = 0`: Return 0. 36 | - `n = 1`: Return 1. 37 | - **Optimizations**: Use array-based DP; can optimize to O(1) space with two variables. 38 | 39 | ## Complexity Analysis 40 | - **Time Complexity**: O(n), single loop from 2 to n. 41 | - **Space Complexity**: O(n) for the DP array. Can be optimized to O(1) using two variables. 42 | 43 | ## Best Practices 44 | - Use clear variable names (e.g., `dp` for dynamic programming array). 45 | - For Python, use type hints for clarity. 46 | - For JavaScript, use array initialization with `fill`. 47 | - For Java, follow Google Java Style Guide. 48 | - Handle base cases early to avoid unnecessary computation. 49 | 50 | ## Alternative Approaches 51 | - **Optimized Space DP**: Use two variables (O(n) time, O(1) space). 52 | - **Recursion with Memoization**: Cache results (O(n) time, O(n) space). Less efficient than iterative. 53 | - **Matrix Exponentiation**: Compute Fibonacci using matrix (O(log n) time). Overkill for small n. -------------------------------------------------------------------------------- /Python/Dynamic_Programming/Easy/fibonacci_number.md: -------------------------------------------------------------------------------- 1 | # Fibonacci Number 2 | 3 | ## Problem Statement 4 | The Fibonacci numbers are defined as: `F(0) = 0`, `F(1) = 1`, and `F(n) = F(n-1) + F(n-2)` for `n > 1`. Given `n`, return the value of `F(n)`. 5 | 6 | **Example**: 7 | - Input: `n = 2` 8 | - Output: `1` 9 | - Explanation: `F(2) = F(1) + F(0) = 1 + 0 = 1`. 10 | 11 | **Constraints**: 12 | - `0 <= n <= 30` 13 | 14 | ## Solution 15 | 16 | ### Java 17 | ```java 18 | class Solution { 19 | public int fib(int n) { 20 | if (n <= 1) return n; 21 | int[] dp = new int[n + 1]; 22 | dp[1] = 1; 23 | for (int i = 2; i <= n; i++) { 24 | dp[i] = dp[i - 1] + dp[i - 2]; 25 | } 26 | return dp[n]; 27 | } 28 | } 29 | ``` 30 | 31 | ## Reasoning 32 | - **Approach**: Use dynamic programming to compute the nth Fibonacci number. Each number is the sum of the previous two: `dp[i] = dp[i-1] + dp[i-2]`. Initialize `dp[0] = 0`, `dp[1] = 1`. 33 | - **Why DP?**: Avoids exponential recursive calls by storing intermediate results. 34 | - **Edge Cases**: 35 | - `n = 0`: Return 0. 36 | - `n = 1`: Return 1. 37 | - **Optimizations**: Use array-based DP; can optimize to O(1) space with two variables. 38 | 39 | ## Complexity Analysis 40 | - **Time Complexity**: O(n), single loop from 2 to n. 41 | - **Space Complexity**: O(n) for the DP array. Can be optimized to O(1) using two variables. 42 | 43 | ## Best Practices 44 | - Use clear variable names (e.g., `dp` for dynamic programming array). 45 | - For Python, use type hints for clarity. 46 | - For JavaScript, use array initialization with `fill`. 47 | - For Java, follow Google Java Style Guide. 48 | - Handle base cases early to avoid unnecessary computation. 49 | 50 | ## Alternative Approaches 51 | - **Optimized Space DP**: Use two variables (O(n) time, O(1) space). 52 | - **Recursion with Memoization**: Cache results (O(n) time, O(n) space). Less efficient than iterative. 53 | - **Matrix Exponentiation**: Compute Fibonacci using matrix (O(log n) time). Overkill for small n. -------------------------------------------------------------------------------- /MySQL/Easy/duplicate_emails.md: -------------------------------------------------------------------------------- 1 | # Duplicate Emails 2 | 3 | ## Problem Statement 4 | Write a SQL query to report all duplicate email addresses in the `Person` table. 5 | 6 | **Table: Person** 7 | ``` 8 | +-------------+---------+ 9 | | Column Name | Type | 10 | +-------------+---------+ 11 | | id | int | 12 | | email | varchar | 13 | +-------------+---------+ 14 | id is the primary key. 15 | ``` 16 | 17 | **Example**: 18 | - Input: `[[1, "a@b.com"], [2, "c@d.com"], [3, "a@b.com"]]` 19 | - Output: `["a@b.com"]` 20 | 21 | **Constraints**: 22 | - `1 <= Person.id <= 1000` 23 | - `email` contains lowercase letters only. 24 | 25 | ## Solution 26 | ```sql 27 | SELECT email 28 | FROM Person 29 | GROUP BY email 30 | HAVING COUNT(*) > 1; 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use `GROUP BY` to group rows by `email` and `HAVING` to filter groups with more than one occurrence. Select the `email` column for duplicates. 35 | - **Why GROUP BY?**: Aggregates rows by email, allowing `COUNT` to identify duplicates efficiently. 36 | - **Edge Cases**: 37 | - No duplicates: Returns empty result. 38 | - Single email: Returns no rows. 39 | - All duplicates: Returns the repeated email. 40 | - **Optimizations**: Simple `GROUP BY` and `HAVING` avoid complex joins or subqueries. 41 | 42 | ## Performance Analysis 43 | - **Time Complexity**: O(n log n) for grouping and counting, depending on database’s hash/sort implementation. 44 | - **Space Complexity**: O(k), where k is the number of unique emails, for storing groups. 45 | - **Index Usage**: An index on `email` improves grouping performance. 46 | 47 | ## Best Practices 48 | - Use `GROUP BY` and `HAVING` for aggregation-based filtering. 49 | - Keep query minimal and readable. 50 | - Avoid unnecessary columns in output. 51 | - Format SQL consistently. 52 | 53 | ## Alternative Approaches 54 | - **Self-Join**: Join table with itself on matching emails (O(n^2), less efficient). 55 | - **Subquery**: Use subquery to count emails (O(n), more complex). 56 | - **Window Function**: Use `COUNT` over partition (O(n log n), overkill). -------------------------------------------------------------------------------- /Python/Sorting_Searching/Medium/kth_largest_element.md: -------------------------------------------------------------------------------- 1 | # Kth Largest Element in an Array 2 | 3 | ## Problem Statement 4 | Given an integer array `nums` and an integer `k`, return the kth largest element in the array. The kth largest element is the kth element in the sorted array in descending order. 5 | 6 | **Example**: 7 | - Input: `nums = [3,2,1,5,6,4], k = 2` 8 | - Output: `5` 9 | 10 | **Constraints**: 11 | - `1 <= k <= nums.length <= 10^5` 12 | - `-10^4 <= nums[i] <= 10^4` 13 | 14 | ## Solution 15 | 16 | ### Python 17 | ```python 18 | import heapq 19 | 20 | def findKthLargest(nums: list[int], k: int) -> int: 21 | heap = [] 22 | for num in nums: 23 | heapq.heappush(heap, num) 24 | if len(heap) > k: 25 | heapq.heappop(heap) 26 | 27 | return heap[0] 28 | ``` 29 | 30 | ## Reasoning 31 | - **Approach**: Use a min-heap of size k to track the k largest elements. For each element, add to the heap and remove the smallest if size exceeds k. The heap’s root is the kth largest element. 32 | - **Why Min-Heap?**: Maintains k largest elements efficiently, with O(log k) insertion and removal, achieving O(n log k) overall. 33 | - **Edge Cases**: 34 | - k=1: Return maximum. 35 | - k=nums.length: Return minimum. 36 | - Single element: Return it if k=1. 37 | - **Optimizations**: Use min-heap to keep only k elements; avoid sorting entire array. 38 | 39 | ## Complexity Analysis 40 | - **Time Complexity**: O(n log k), where n is the length of `nums`, as each insertion/removal is O(log k). 41 | - **Space Complexity**: O(k), for the min-heap. 42 | 43 | ## Best Practices 44 | - Use clear variable names (e.g., `heap`). 45 | - For Python, use `heapq` with type hints. 46 | - For JavaScript, use a min-priority queue library. 47 | - For Java, use `PriorityQueue` and follow Google Java Style Guide. 48 | - Limit heap size to k for efficiency. 49 | 50 | ## Alternative Approaches 51 | - **Sorting**: Sort array and pick kth element (O(n log n) time). Less efficient. 52 | - **QuickSelect**: Use partitioning to find kth largest (O(n) average time, O(1) space). More complex. -------------------------------------------------------------------------------- /Python/Linked_Lists/Easy/middle_of_linked_list.md: -------------------------------------------------------------------------------- 1 | # Middle of the Linked List 2 | 3 | ## Problem Statement 4 | Given the head of a singly linked list, return the middle node. If there are two middle nodes, return the second one. 5 | 6 | **Example**: 7 | - Input: `head = [1,2,3,4,5]` 8 | - Output: `[3,4,5]` 9 | 10 | **Constraints**: 11 | - The number of nodes in the list is in the range `[1, 100]`. 12 | - `1 <= Node.val <= 100` 13 | 14 | ## Solution 15 | 16 | ### Python 17 | ```python 18 | class ListNode: 19 | def __init__(self, val=0, next=None): 20 | self.val = val 21 | self.next = next 22 | 23 | def middleNode(head: ListNode) -> ListNode: 24 | slow = fast = head 25 | while fast and fast.next: 26 | slow = slow.next 27 | fast = fast.next.next 28 | return slow 29 | ``` 30 | 31 | ## Reasoning 32 | - **Approach**: Use the two-pointer technique (slow and fast pointers). Slow moves one step, fast moves two steps. When fast reaches the end, slow is at the middle. For even-length lists, slow lands on the second middle node. 33 | - **Why Two Pointers?**: Finds the middle in one pass without counting nodes, using O(1) space. 34 | - **Edge Cases**: 35 | - Single node: Return the head. 36 | - Even number of nodes: Return the second middle node. 37 | - **Optimizations**: Single pass with two pointers; no extra space needed. 38 | 39 | ## Complexity Analysis 40 | - **Time Complexity**: O(n), where n is the number of nodes, as we traverse the list once. 41 | - **Space Complexity**: O(1), as only two pointers are used. 42 | 43 | ## Best Practices 44 | - Use clear variable names (e.g., `slow`, `fast`). 45 | - For Python, use type hints for clarity. 46 | - For JavaScript, use concise pointer updates. 47 | - For Java, follow Google Java Style Guide. 48 | - Handle null checks in the loop condition. 49 | 50 | ## Alternative Approaches 51 | - **Count and Find**: Count nodes, then traverse to the middle (O(n) time, O(1) space). Two passes, less efficient. 52 | - **Array-Based**: Store nodes in an array and return middle (O(n) time, O(n) space). Less space-efficient. -------------------------------------------------------------------------------- /Python/Linked_Lists/Easy/reverse_linked_list.md: -------------------------------------------------------------------------------- 1 | # Reverse Linked List 2 | 3 | ## Problem Statement 4 | Given the head of a singly linked list, reverse the list and return its head. 5 | 6 | **Example**: 7 | - Input: `head = [1,2,3,4,5]` 8 | - Output: `[5,4,3,2,1]` 9 | 10 | **Constraints**: 11 | - The number of nodes in the list is in the range `[0, 5000]`. 12 | - `-5000 <= Node.val <= 5000` 13 | 14 | ## Solution 15 | 16 | ### Python 17 | ```python 18 | class ListNode: 19 | def __init__(self, val=0, next=None): 20 | self.val = val 21 | self.next = next 22 | 23 | def reverseList(head: ListNode) -> ListNode: 24 | prev = None 25 | current = head 26 | 27 | while current: 28 | next_node = current.next 29 | current.next = prev 30 | prev = current 31 | current = next_node 32 | 33 | return prev 34 | ``` 35 | 36 | ## Reasoning 37 | - **Approach**: Iteratively reverse the list by adjusting pointers. For each node, save the next node, point the current node’s next to the previous node, and move forward. The `prev` node becomes the new head. 38 | - **Why Iterative?**: Avoids recursion stack space, making it more efficient for large lists. 39 | - **Edge Cases**: 40 | - Empty list: Return null. 41 | - Single node: Return the node. 42 | - **Optimizations**: In-place reversal to minimize space; single pass through the list. 43 | 44 | ## Complexity Analysis 45 | - **Time Complexity**: O(n), where n is the number of nodes, as we traverse the list once. 46 | - **Space Complexity**: O(1), as we only use a few pointers. 47 | 48 | ## Best Practices 49 | - Use clear variable names (e.g., `prev`, `current`). 50 | - For Python, use type hints for clarity. 51 | - For JavaScript, use descriptive variable names. 52 | - For Java, follow Google Java Style Guide. 53 | - Handle null checks explicitly. 54 | 55 | ## Alternative Approaches 56 | - **Recursive**: Recursively reverse by adjusting pointers (O(n) time, O(n) space due to recursion stack). 57 | - **Stack-Based**: Push nodes onto a stack and pop to reverse (O(n) time, O(n) space). Less efficient. -------------------------------------------------------------------------------- /JavaScript/Sorting_Searching/Medium/kth_largest_element.md: -------------------------------------------------------------------------------- 1 | # Kth Largest Element in an Array 2 | 3 | ## Problem Statement 4 | Given an integer array `nums` and an integer `k`, return the kth largest element in the array. The kth largest element is the kth element in the sorted array in descending order. 5 | 6 | **Example**: 7 | - Input: `nums = [3,2,1,5,6,4], k = 2` 8 | - Output: `5` 9 | 10 | **Constraints**: 11 | - `1 <= k <= nums.length <= 10^5` 12 | - `-10^4 <= nums[i] <= 10^4` 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | function findKthLargest(nums, k) { 19 | const heap = new MinPriorityQueue(); 20 | for (const num of nums) { 21 | heap.enqueue(num); 22 | if (heap.size() > k) heap.dequeue(); 23 | } 24 | 25 | return heap.front().element; 26 | } 27 | ``` 28 | 29 | ## Reasoning 30 | - **Approach**: Use a min-heap of size k to track the k largest elements. For each element, add to the heap and remove the smallest if size exceeds k. The heap’s root is the kth largest element. 31 | - **Why Min-Heap?**: Maintains k largest elements efficiently, with O(log k) insertion and removal, achieving O(n log k) overall. 32 | - **Edge Cases**: 33 | - k=1: Return maximum. 34 | - k=nums.length: Return minimum. 35 | - Single element: Return it if k=1. 36 | - **Optimizations**: Use min-heap to keep only k elements; avoid sorting entire array. 37 | 38 | ## Complexity Analysis 39 | - **Time Complexity**: O(n log k), where n is the length of `nums`, as each insertion/removal is O(log k). 40 | - **Space Complexity**: O(k), for the min-heap. 41 | 42 | ## Best Practices 43 | - Use clear variable names (e.g., `heap`). 44 | - For Python, use `heapq` with type hints. 45 | - For JavaScript, use a min-priority queue library. 46 | - For Java, use `PriorityQueue` and follow Google Java Style Guide. 47 | - Limit heap size to k for efficiency. 48 | 49 | ## Alternative Approaches 50 | - **Sorting**: Sort array and pick kth element (O(n log n) time). Less efficient. 51 | - **QuickSelect**: Use partitioning to find kth largest (O(n) average time, O(1) space). More complex. -------------------------------------------------------------------------------- /Python/Arrays/Medium/rotate_array.md: -------------------------------------------------------------------------------- 1 | # Rotate Array 2 | 3 | ## Problem Statement 4 | Given an integer array `nums`, rotate the array to the right by `k` steps, where `k` is non-negative. The operation must be done in-place. 5 | 6 | **Example**: 7 | - Input: `nums = [1,2,3,4,5,6,7], k = 3` 8 | - Output: `[5,6,7,1,2,3,4]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 10^5` 12 | - `-2^31 <= nums[i] <= 2^31 - 1` 13 | - `0 <= k <= 10^5` 14 | 15 | ## Solution 16 | 17 | ### Python 18 | ```python 19 | def rotate(nums: list[int], k: int) -> None: 20 | n = len(nums) 21 | k = k % n 22 | def reverse(start: int, end: int) -> None: 23 | while start < end: 24 | nums[start], nums[end] = nums[end], nums[start] 25 | start += 1 26 | end -= 1 27 | reverse(0, n - 1) 28 | reverse(0, k - 1) 29 | reverse(k, n - 1) 30 | ``` 31 | 32 | ## Reasoning 33 | - **Approach**: Use the reverse array method: reverse the entire array, then reverse the first `k` elements, then reverse the rest. This effectively rotates the array right by `k` steps in-place. 34 | - **Why Reverse?**: It’s an elegant way to achieve rotation in-place with O(n) time and O(1) space. 35 | - **Edge Cases**: 36 | - `k > n`: Use `k % n` to handle large `k`. 37 | - `k = 0` or `n = 1`: No rotation needed. 38 | - **Optimizations**: Modulo `k` to handle large rotations; in-place swaps to minimize space. 39 | 40 | ## Complexity Analysis 41 | - **Time Complexity**: O(n), where n is the length of `nums`. Three reverse passes. 42 | - **Space Complexity**: O(1), as operations are in-place. 43 | 44 | ## Best Practices 45 | - Use clear function names (e.g., `reverse`). 46 | - For Python, use type hints and modular helper functions. 47 | - For JavaScript, use array destructuring for swaps. 48 | - For Java, use private helper methods and follow Google Java Style Guide. 49 | - Handle large `k` with modulo. 50 | 51 | ## Alternative Approaches 52 | - **Cyclic Replacements**: Move each element to its new position (O(n) time, O(1) space). Complex to implement. 53 | - **Extra Array**: Copy elements to new positions (O(n) time, O(n) space). Not in-place. -------------------------------------------------------------------------------- /Java/Trees/Easy/maximum_depth_of_binary_tree.md: -------------------------------------------------------------------------------- 1 | # Maximum Depth of Binary Tree 2 | 3 | ## Problem Statement 4 | Given the root of a binary tree, return its maximum depth. The maximum depth is the number of nodes along the longest path from the root to a leaf. 5 | 6 | **Example**: 7 | - Input: `root = [3,9,20,null,null,15,7]` 8 | - Output: `3` 9 | 10 | **Constraints**: 11 | - The number of nodes is in the range `[0, 10^4]`. 12 | - `-100 <= Node.val <= 100` 13 | 14 | ## Solution 15 | 16 | ### Java 17 | ```java 18 | class Solution { 19 | public int maxDepth(TreeNode root) { 20 | if (root == null) return 0; 21 | int leftDepth = maxDepth(root.left); 22 | int rightDepth = maxDepth(root.right); 23 | return Math.max(leftDepth, rightDepth) + 1; 24 | } 25 | } 26 | ``` 27 | 28 | ## Reasoning 29 | - **Approach**: Use recursive depth calculation. For each node, compute the maximum depth of left and right subtrees and return the maximum plus 1 (for the current node). 30 | - **Why Recursive?**: Depth calculation naturally decomposes into subproblems, making recursion simple and intuitive. 31 | - **Edge Cases**: 32 | - Empty tree: Return 0. 33 | - Single node: Return 1. 34 | - Skewed tree: Depth equals length of path. 35 | - **Optimizations**: Recursive solution is concise; iterative BFS/DFS possible but not simpler. 36 | 37 | ## Complexity Analysis 38 | - **Time Complexity**: O(n), where n is the number of nodes, as each node is visited once. 39 | - **Space Complexity**: O(h), where h is the height of the tree, due to the recursion stack (O(n) in worst case for skewed tree). 40 | 41 | ## Best Practices 42 | - Use clear variable names (e.g., `leftDepth`, `rightDepth`). 43 | - For Python, use type hints. 44 | - For JavaScript, use `Math.max` for clarity. 45 | - For Java, follow Google Java Style Guide. 46 | - Keep recursion straightforward. 47 | 48 | ## Alternative Approaches 49 | - **Iterative BFS**: Use a queue to process levels (O(n) time, O(w) space, where w is max width). Suitable for wide trees. 50 | - **Iterative DFS**: Use a stack with depth tracking (O(n) time, O(h) space). Similar complexity but more complex code. -------------------------------------------------------------------------------- /JavaScript/Linked_Lists/Easy/middle_of_linked_list.md: -------------------------------------------------------------------------------- 1 | # Middle of the Linked List 2 | 3 | ## Problem Statement 4 | Given the head of a singly linked list, return the middle node. If there are two middle nodes, return the second one. 5 | 6 | **Example**: 7 | - Input: `head = [1,2,3,4,5]` 8 | - Output: `[3,4,5]` 9 | 10 | **Constraints**: 11 | - The number of nodes in the list is in the range `[1, 100]`. 12 | - `1 <= Node.val <= 100` 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | function ListNode(val, next) { 19 | this.val = (val === undefined ? 0 : val); 20 | this.next = (next === undefined ? null : next); 21 | } 22 | 23 | function middleNode(head) { 24 | let slow = head, fast = head; 25 | while (fast && fast.next) { 26 | slow = slow.next; 27 | fast = fast.next.next; 28 | } 29 | return slow; 30 | } 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use the two-pointer technique (slow and fast pointers). Slow moves one step, fast moves two steps. When fast reaches the end, slow is at the middle. For even-length lists, slow lands on the second middle node. 35 | - **Why Two Pointers?**: Finds the middle in one pass without counting nodes, using O(1) space. 36 | - **Edge Cases**: 37 | - Single node: Return the head. 38 | - Even number of nodes: Return the second middle node. 39 | - **Optimizations**: Single pass with two pointers; no extra space needed. 40 | 41 | ## Complexity Analysis 42 | - **Time Complexity**: O(n), where n is the number of nodes, as we traverse the list once. 43 | - **Space Complexity**: O(1), as only two pointers are used. 44 | 45 | ## Best Practices 46 | - Use clear variable names (e.g., `slow`, `fast`). 47 | - For Python, use type hints for clarity. 48 | - For JavaScript, use concise pointer updates. 49 | - For Java, follow Google Java Style Guide. 50 | - Handle null checks in the loop condition. 51 | 52 | ## Alternative Approaches 53 | - **Count and Find**: Count nodes, then traverse to the middle (O(n) time, O(1) space). Two passes, less efficient. 54 | - **Array-Based**: Store nodes in an array and return middle (O(n) time, O(n) space). Less space-efficient. -------------------------------------------------------------------------------- /Numpy/Medium/array_sorting.md: -------------------------------------------------------------------------------- 1 | # Array Sorting 2 | 3 | ## Problem Statement 4 | Write a NumPy program to sort a 2D array by a specific column. 5 | 6 | **Input**: 7 | - `arr`: 2D array of shape `(m, n)` (e.g., `[[3, 1], [1, 2], [2, 3]]`) 8 | - `col`: Column index to sort by (e.g., `1`) 9 | 10 | **Output**: 11 | - Sorted 2D array (e.g., `[[3, 1], [1, 2], [2, 3]]`) 12 | 13 | **Constraints**: 14 | - `1 <= m, n <= 1000` 15 | - `0 <= col < n` 16 | - `-10^5 <= arr[i][j] <= 10^5` 17 | 18 | ## Solution 19 | ```python 20 | import numpy as np 21 | 22 | def array_sorting(arr: list, col: int) -> np.ndarray: 23 | # Convert to numpy array and sort by column 24 | return np.array(arr)[np.argsort(np.array(arr)[:, col])] 25 | ``` 26 | 27 | ## Reasoning 28 | - **Approach**: Convert input list to NumPy array. Use `np.argsort` on the specified column to get sorted indices. Index the array with these indices to sort rows. Return the result. 29 | - **Why np.argsort?**: Efficiently sorts indices, preserving row integrity. 30 | - **Edge Cases**: 31 | - Single row: Returns same array. 32 | - Invalid column: Ensured by `col < n`. 33 | - Ties in column: `np.argsort` uses stable sorting. 34 | - **Optimizations**: `np.argsort` is optimized for performance. 35 | 36 | ## Performance Analysis 37 | - **Time Complexity**: O(m log m), where m is the number of rows, for sorting. 38 | - **Space Complexity**: O(m) for the index array and output. 39 | - **NumPy Efficiency**: `np.argsort` uses optimized C-based sorting. 40 | 41 | ## Best Practices 42 | - Use `np.argsort` for sorting by column. 43 | - Validate `col` to avoid out-of-bounds errors. 44 | - Follow PEP 8 for Python code style. 45 | 46 | ## Alternative Approaches 47 | - **Manual Sorting**: Sort manually (O(m log m), slower). 48 | ```python 49 | def array_sorting(arr: list, col: int) -> list: 50 | return sorted(arr, key=lambda x: x[col]) 51 | ``` 52 | - **np.sort**: Use structured sorting (O(m log m), similar performance). 53 | ```python 54 | import numpy as np 55 | def array_sorting(arr: list, col: int) -> np.ndarray: 56 | arr = np.array(arr) 57 | return arr[arr[:, col].argsort()] 58 | ``` -------------------------------------------------------------------------------- /JavaScript/Trees/Easy/maximum_depth_of_binary_tree.md: -------------------------------------------------------------------------------- 1 | # Maximum Depth of Binary Tree 2 | 3 | ## Problem Statement 4 | Given the root of a binary tree, return its maximum depth. The maximum depth is the number of nodes along the longest path from the root to a leaf. 5 | 6 | **Example**: 7 | - Input: `root = [3,9,20,null,null,15,7]` 8 | - Output: `3` 9 | 10 | **Constraints**: 11 | - The number of nodes is in the range `[0, 10^4]`. 12 | - `-100 <= Node.val <= 100` 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | class Solution { 19 | maxDepth(root) { 20 | if (!root) return 0; 21 | const leftDepth = this.maxDepth(root.left); 22 | const rightDepth = this.maxDepth(root.right); 23 | return Math.max(leftDepth, rightDepth) + 1; 24 | } 25 | } 26 | ``` 27 | 28 | ## Reasoning 29 | - **Approach**: Use recursive depth calculation. For each node, compute the maximum depth of left and right subtrees and return the maximum plus 1 (for the current node). 30 | - **Why Recursive?**: Depth calculation naturally decomposes into subproblems, making recursion simple and intuitive. 31 | - **Edge Cases**: 32 | - Empty tree: Return 0. 33 | - Single node: Return 1. 34 | - Skewed tree: Depth equals length of path. 35 | - **Optimizations**: Recursive solution is concise; iterative BFS/DFS possible but not simpler. 36 | 37 | ## Complexity Analysis 38 | - **Time Complexity**: O(n), where n is the number of nodes, as each node is visited once. 39 | - **Space Complexity**: O(h), where h is the height of the tree, due to the recursion stack (O(n) in worst case for skewed tree). 40 | 41 | ## Best Practices 42 | - Use clear variable names (e.g., `leftDepth`, `rightDepth`). 43 | - For Python, use type hints. 44 | - For JavaScript, use `Math.max` for clarity. 45 | - For Java, follow Google Java Style Guide. 46 | - Keep recursion straightforward. 47 | 48 | ## Alternative Approaches 49 | - **Iterative BFS**: Use a queue to process levels (O(n) time, O(w) space, where w is max width). Suitable for wide trees. 50 | - **Iterative DFS**: Use a stack with depth tracking (O(n) time, O(h) space). Similar complexity but more complex code. -------------------------------------------------------------------------------- /Numpy/Easy/array_indexing.md: -------------------------------------------------------------------------------- 1 | # Array Indexing 2 | 3 | ## Problem Statement 4 | Write a NumPy program to extract elements from a 1D array using a list of indices. 5 | 6 | **Input**: 7 | - `arr`: 1D array of numbers (e.g., `[10, 20, 30, 40, 50]`) 8 | - `indices`: 1D array of indices (e.g., `[0, 2, 4]`) 9 | 10 | **Output**: 11 | - 1D array of elements at specified indices (e.g., `[10, 30, 50]`) 12 | 13 | **Constraints**: 14 | - `1 <= len(arr) <= 10^5` 15 | - `1 <= len(indices) <= len(arr)` 16 | - `0 <= indices[i] < len(arr)` 17 | - `-10^5 <= arr[i] <= 10^5` 18 | 19 | ## Solution 20 | ```python 21 | import numpy as np 22 | 23 | def array_indexing(arr: list, indices: list) -> np.ndarray: 24 | # Convert to numpy arrays and index 25 | return np.array(arr)[indices] 26 | ``` 27 | 28 | ## Reasoning 29 | - **Approach**: Convert input list to NumPy array. Use NumPy’s advanced indexing with `indices` to extract elements. Return the result. 30 | - **Why NumPy indexing?**: Fast and concise compared to Python list indexing. 31 | - **Edge Cases**: 32 | - Empty indices: Returns empty array. 33 | - Single index: Returns single-element array. 34 | - Invalid indices: Ensured by constraints. 35 | - **Optimizations**: NumPy’s indexing is optimized for performance. 36 | 37 | ## Performance Analysis 38 | - **Time Complexity**: O(k), where k is the length of indices, for indexing operation. 39 | - **Space Complexity**: O(k) for the output array. 40 | - **NumPy Efficiency**: Advanced indexing is implemented in C for speed. 41 | 42 | ## Best Practices 43 | - Use NumPy’s advanced indexing for efficiency. 44 | - Validate indices to avoid out-of-bounds errors. 45 | - Follow PEP 8 for Python code style. 46 | 47 | ## Alternative Approaches 48 | - **Python List Indexing**: Manual indexing (O(k), slower). 49 | ```python 50 | def array_indexing(arr: list, indices: list) -> list: 51 | return [arr[i] for i in indices] 52 | ``` 53 | - **np.take**: Explicit indexing function (O(k), same performance). 54 | ```python 55 | import numpy as np 56 | def array_indexing(arr: list, indices: list) -> np.ndarray: 57 | return np.take(np.array(arr), indices) 58 | ``` -------------------------------------------------------------------------------- /Python/Trees/Easy/maximum_depth_of_binary_tree.md: -------------------------------------------------------------------------------- 1 | # Maximum Depth of Binary Tree 2 | 3 | ## Problem Statement 4 | Given the root of a binary tree, return its maximum depth. The maximum depth is the number of nodes along the longest path from the root to a leaf. 5 | 6 | **Example**: 7 | - Input: `root = [3,9,20,null,null,15,7]` 8 | - Output: `3` 9 | 10 | **Constraints**: 11 | - The number of nodes is in the range `[0, 10^4]`. 12 | - `-100 <= Node.val <= 100` 13 | 14 | ## Solution 15 | 16 | ### Python 17 | ```python 18 | class Solution: 19 | def maxDepth(self, root: TreeNode) -> int: 20 | if not root: 21 | return 0 22 | left_depth = self.maxDepth(root.left) 23 | right_depth = self.maxDepth(root.right) 24 | return max(left_depth, right_depth) + 1 25 | ``` 26 | 27 | ## Reasoning 28 | - **Approach**: Use recursive depth calculation. For each node, compute the maximum depth of left and right subtrees and return the maximum plus 1 (for the current node). 29 | - **Why Recursive?**: Depth calculation naturally decomposes into subproblems, making recursion simple and intuitive. 30 | - **Edge Cases**: 31 | - Empty tree: Return 0. 32 | - Single node: Return 1. 33 | - Skewed tree: Depth equals length of path. 34 | - **Optimizations**: Recursive solution is concise; iterative BFS/DFS possible but not simpler. 35 | 36 | ## Complexity Analysis 37 | - **Time Complexity**: O(n), where n is the number of nodes, as each node is visited once. 38 | - **Space Complexity**: O(h), where h is the height of the tree, due to the recursion stack (O(n) in worst case for skewed tree). 39 | 40 | ## Best Practices 41 | - Use clear variable names (e.g., `leftDepth`, `rightDepth`). 42 | - For Python, use type hints. 43 | - For JavaScript, use `Math.max` for clarity. 44 | - For Java, follow Google Java Style Guide. 45 | - Keep recursion straightforward. 46 | 47 | ## Alternative Approaches 48 | - **Iterative BFS**: Use a queue to process levels (O(n) time, O(w) space, where w is max width). Suitable for wide trees. 49 | - **Iterative DFS**: Use a stack with depth tracking (O(n) time, O(h) space). Similar complexity but more complex code. -------------------------------------------------------------------------------- /JavaScript/Linked_Lists/Easy/reverse_linked_list.md: -------------------------------------------------------------------------------- 1 | # Reverse Linked List 2 | 3 | ## Problem Statement 4 | Given the head of a singly linked list, reverse the list and return its head. 5 | 6 | **Example**: 7 | - Input: `head = [1,2,3,4,5]` 8 | - Output: `[5,4,3,2,1]` 9 | 10 | **Constraints**: 11 | - The number of nodes in the list is in the range `[0, 5000]`. 12 | - `-5000 <= Node.val <= 5000` 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | function ListNode(val, next) { 19 | this.val = (val === undefined ? 0 : val); 20 | this.next = (next === undefined ? null : next); 21 | } 22 | 23 | function reverseList(head) { 24 | let prev = null; 25 | let current = head; 26 | 27 | while (current) { 28 | const nextNode = current.next; 29 | current.next = prev; 30 | prev = current; 31 | current = nextNode; 32 | } 33 | 34 | return prev; 35 | } 36 | ``` 37 | 38 | ## Reasoning 39 | - **Approach**: Iteratively reverse the list by adjusting pointers. For each node, save the next node, point the current node’s next to the previous node, and move forward. The `prev` node becomes the new head. 40 | - **Why Iterative?**: Avoids recursion stack space, making it more efficient for large lists. 41 | - **Edge Cases**: 42 | - Empty list: Return null. 43 | - Single node: Return the node. 44 | - **Optimizations**: In-place reversal to minimize space; single pass through the list. 45 | 46 | ## Complexity Analysis 47 | - **Time Complexity**: O(n), where n is the number of nodes, as we traverse the list once. 48 | - **Space Complexity**: O(1), as we only use a few pointers. 49 | 50 | ## Best Practices 51 | - Use clear variable names (e.g., `prev`, `current`). 52 | - For Python, use type hints for clarity. 53 | - For JavaScript, use descriptive variable names. 54 | - For Java, follow Google Java Style Guide. 55 | - Handle null checks explicitly. 56 | 57 | ## Alternative Approaches 58 | - **Recursive**: Recursively reverse by adjusting pointers (O(n) time, O(n) space due to recursion stack). 59 | - **Stack-Based**: Push nodes onto a stack and pop to reverse (O(n) time, O(n) space). Less efficient. -------------------------------------------------------------------------------- /Python/Arrays/Hard/first_missing_positive.md: -------------------------------------------------------------------------------- 1 | # First Missing Positive 2 | 3 | ## Problem Statement 4 | Given an unsorted integer array `nums`, return the smallest missing positive integer. You must implement an algorithm that runs in O(n) time and uses O(1) space. 5 | 6 | **Example**: 7 | - Input: `nums = [1,2,0]` 8 | - Output: `3` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 5 * 10^5` 12 | - `-2^31 <= nums[i] <= 2^31 - 1` 13 | 14 | ## Solution 15 | 16 | ### Python 17 | ```python 18 | def firstMissingPositive(nums: list[int]) -> int: 19 | n = len(nums) 20 | for i in range(n): 21 | if nums[i] <= 0 or nums[i] > n: 22 | nums[i] = n + 1 23 | for i in range(n): 24 | num = abs(nums[i]) 25 | if num <= n: 26 | nums[num - 1] = -abs(nums[num - 1]) 27 | for i in range(n): 28 | if nums[i] > 0: 29 | return i + 1 30 | return n + 1 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use the array itself as a hash table. Ignore non-positive and numbers > n. Place each number `x` at index `x-1` by marking the index negative. The first positive index indicates the missing number. 35 | - **Why In-Place Marking?**: Achieves O(1) space by using the array to track presence of numbers 1 to n. 36 | - **Edge Cases**: 37 | - Empty array: Return 1. 38 | - All numbers present: Return n + 1. 39 | - Negative numbers: Ignored via preprocessing. 40 | - **Optimizations**: Three linear passes; no extra space. 41 | 42 | ## Complexity Analysis 43 | - **Time Complexity**: O(n), where n is the length of `nums`. Three passes through the array. 44 | - **Space Complexity**: O(1), using the array itself. 45 | 46 | ## Best Practices 47 | - Use clear variable names (e.g., `num`, `n`). 48 | - For Python, use type hints and handle edge cases. 49 | - For JavaScript, use `Math.abs` for clarity. 50 | - For Java, follow Google Java Style Guide. 51 | - Use array indices to avoid extra space. 52 | 53 | ## Alternative Approaches 54 | - **Hash Set**: Store numbers and check for missing (O(n) time, O(n) space). Violates space constraint. 55 | - **Sorting**: Sort and find missing number (O(n log n) time). Too slow. -------------------------------------------------------------------------------- /Python/Arrays/Easy/move_zeroes.md: -------------------------------------------------------------------------------- 1 | # Move Zeroes 2 | 3 | ## Problem Statement 4 | Given an integer array `nums`, move all `0`’s to the end of the array while maintaining the relative order of non-zero elements. The operation must be done in-place. 5 | 6 | **Example**: 7 | - Input: `nums = [0,1,0,3,12]` 8 | - Output: `[1,3,12,0,0]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 10^4` 12 | - `-2^31 <= nums[i] <= 2^31 - 1` 13 | 14 | ## Solution 15 | 16 | ### Python 17 | ```python 18 | def moveZeroes(nums: list[int]) -> None: 19 | non_zero_pos = 0 20 | for i in range(len(nums)): 21 | if nums[i] != 0: 22 | nums[non_zero_pos], nums[i] = nums[i], nums[non_zero_pos] 23 | non_zero_pos += 1 24 | ``` 25 | 26 | ## Reasoning 27 | - **Approach**: Use two pointers. Move all non-zero elements to the front by swapping with the `non_zero_pos` index, incrementing it each time. Zeros naturally shift to the end as non-zero elements are placed earlier. 28 | - **Why Two Pointers?**: This ensures in-place operation and maintains relative order without extra space. 29 | - **Edge Cases**: 30 | - All zeros or no zeros: Works correctly without special handling. 31 | - Single element: No change needed. 32 | - **Optimizations**: Single pass to move non-zeros; no need to explicitly set zeros at the end since swaps handle it. 33 | 34 | ## Complexity Analysis 35 | - **Time Complexity**: O(n), where n is the length of `nums`. Single pass through the array. 36 | - **Space Complexity**: O(1), as operations are in-place. 37 | 38 | ## Best Practices 39 | - Use descriptive variable names (e.g., `non_zero_pos`). 40 | - For Python, use type hints and ensure in-place modification. 41 | - For JavaScript, use array destructuring for clean swaps. 42 | - For Java, use explicit temporary variables for swaps and follow Google Java Style Guide. 43 | - Avoid unnecessary passes or extra arrays. 44 | 45 | ## Alternative Approaches 46 | - **Two Passes**: Move non-zeros to the front, then fill the rest with zeros (O(n) time, O(1) space). Less efficient due to extra pass. 47 | - **Extra Array**: Copy non-zeros to a new array, then zeros (O(n) time, O(n) space). Not in-place. -------------------------------------------------------------------------------- /JavaScript/Arrays/Medium/rotate_array.md: -------------------------------------------------------------------------------- 1 | # Rotate Array 2 | 3 | ## Problem Statement 4 | Given an integer array `nums`, rotate the array to the right by `k` steps, where `k` is non-negative. The operation must be done in-place. 5 | 6 | **Example**: 7 | - Input: `nums = [1,2,3,4,5,6,7], k = 3` 8 | - Output: `[5,6,7,1,2,3,4]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 10^5` 12 | - `-2^31 <= nums[i] <= 2^31 - 1` 13 | - `0 <= k <= 10^5` 14 | 15 | ## Solution 16 | 17 | ### JavaScript 18 | ```javascript 19 | function rotate(nums, k) { 20 | const n = nums.length; 21 | k = k % n; 22 | function reverse(start, end) { 23 | while (start < end) { 24 | [nums[start], nums[end]] = [nums[end], nums[start]]; 25 | start++; 26 | end--; 27 | } 28 | } 29 | reverse(0, n - 1); 30 | reverse(0, k - 1); 31 | reverse(k, n - 1); 32 | } 33 | ``` 34 | 35 | ## Reasoning 36 | - **Approach**: Use the reverse array method: reverse the entire array, then reverse the first `k` elements, then reverse the rest. This effectively rotates the array right by `k` steps in-place. 37 | - **Why Reverse?**: It’s an elegant way to achieve rotation in-place with O(n) time and O(1) space. 38 | - **Edge Cases**: 39 | - `k > n`: Use `k % n` to handle large `k`. 40 | - `k = 0` or `n = 1`: No rotation needed. 41 | - **Optimizations**: Modulo `k` to handle large rotations; in-place swaps to minimize space. 42 | 43 | ## Complexity Analysis 44 | - **Time Complexity**: O(n), where n is the length of `nums`. Three reverse passes. 45 | - **Space Complexity**: O(1), as operations are in-place. 46 | 47 | ## Best Practices 48 | - Use clear function names (e.g., `reverse`). 49 | - For Python, use type hints and modular helper functions. 50 | - For JavaScript, use array destructuring for swaps. 51 | - For Java, use private helper methods and follow Google Java Style Guide. 52 | - Handle large `k` with modulo. 53 | 54 | ## Alternative Approaches 55 | - **Cyclic Replacements**: Move each element to its new position (O(n) time, O(1) space). Complex to implement. 56 | - **Extra Array**: Copy elements to new positions (O(n) time, O(n) space). Not in-place. -------------------------------------------------------------------------------- /Java/Sorting_Searching/Medium/kth_largest_element.md: -------------------------------------------------------------------------------- 1 | # Kth Largest Element in an Array 2 | 3 | ## Problem Statement 4 | Given an integer array `nums` and an integer `k`, return the kth largest element in the array. The kth largest element is the kth element in the sorted array in descending order. 5 | 6 | **Example**: 7 | - Input: `nums = [3,2,1,5,6,4], k = 2` 8 | - Output: `5` 9 | 10 | **Constraints**: 11 | - `1 <= k <= nums.length <= 10^5` 12 | - `-10^4 <= nums[i] <= 10^4` 13 | 14 | ## Solution 15 | 16 | ### Java 17 | ```java 18 | import java.util.PriorityQueue; 19 | 20 | class Solution { 21 | public int findKthLargest(int[] nums, int k) { 22 | PriorityQueue heap = new PriorityQueue<>(); 23 | for (int num : nums) { 24 | heap.offer(num); 25 | if (heap.size() > k) heap.poll(); 26 | } 27 | 28 | return heap.peek(); 29 | } 30 | } 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use a min-heap of size k to track the k largest elements. For each element, add to the heap and remove the smallest if size exceeds k. The heap’s root is the kth largest element. 35 | - **Why Min-Heap?**: Maintains k largest elements efficiently, with O(log k) insertion and removal, achieving O(n log k) overall. 36 | - **Edge Cases**: 37 | - k=1: Return maximum. 38 | - k=nums.length: Return minimum. 39 | - Single element: Return it if k=1. 40 | - **Optimizations**: Use min-heap to keep only k elements; avoid sorting entire array. 41 | 42 | ## Complexity Analysis 43 | - **Time Complexity**: O(n log k), where n is the length of `nums`, as each insertion/removal is O(log k). 44 | - **Space Complexity**: O(k), for the min-heap. 45 | 46 | ## Best Practices 47 | - Use clear variable names (e.g., `heap`). 48 | - For Python, use `heapq` with type hints. 49 | - For JavaScript, use a min-priority queue library. 50 | - For Java, use `PriorityQueue` and follow Google Java Style Guide. 51 | - Limit heap size to k for efficiency. 52 | 53 | ## Alternative Approaches 54 | - **Sorting**: Sort array and pick kth element (O(n log n) time). Less efficient. 55 | - **QuickSelect**: Use partitioning to find kth largest (O(n) average time, O(1) space). More complex. -------------------------------------------------------------------------------- /JavaScript/Trees/Easy/same_tree.md: -------------------------------------------------------------------------------- 1 | # Same Tree 2 | 3 | ## Problem Statement 4 | Given the roots of two binary trees `p` and `q`, 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. 5 | 6 | **Example**: 7 | - Input: `p = [1,2,3], q = [1,2,3]` 8 | - Output: `true` 9 | 10 | **Constraints**: 11 | - The number of nodes in both trees is in the range `[0, 100]`. 12 | - `-10^4 <= Node.val <= 10^4` 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | class Solution { 19 | isSameTree(p, q) { 20 | if (!p && !q) return true; 21 | if (!p || !q) return false; 22 | return (p.val === q.val && 23 | this.isSameTree(p.left, q.left) && 24 | this.isSameTree(p.right, q.right)); 25 | } 26 | } 27 | ``` 28 | 29 | ## Reasoning 30 | - **Approach**: Use recursive comparison. Check if both nodes are null (same), one is null (different), or values differ. Recurse on left and right subtrees. 31 | - **Why Recursive?**: Tree comparison decomposes into checking corresponding nodes and subtrees, making recursion natural and concise. 32 | - **Edge Cases**: 33 | - Both empty: Return true. 34 | - One empty: Return false. 35 | - Single node: Compare values. 36 | - **Optimizations**: Recursive solution is minimal; iterative possible but not simpler. 37 | 38 | ## Complexity Analysis 39 | - **Time Complexity**: O(n), where n is the minimum number of nodes in `p` or `q`, as each node is visited once. 40 | - **Space Complexity**: O(h), where h is the height of the smaller tree, due to the recursion stack (O(n) in worst case for skewed tree). 41 | 42 | ## Best Practices 43 | - Use clear variable names (e.g., `p`, `q`). 44 | - For Python, use type hints. 45 | - For JavaScript, use strict equality (`===`). 46 | - For Java, follow Google Java Style Guide. 47 | - Keep comparison logic concise. 48 | 49 | ## Alternative Approaches 50 | - **Iterative BFS**: Use a queue to compare nodes level-by-level (O(n) time, O(w) space, where w is max width). More complex. 51 | - **Iterative DFS**: Use a stack to compare nodes (O(n) time, O(h) space). Similar complexity but less intuitive. -------------------------------------------------------------------------------- /JavaScript/Dynamic_Programming/Easy/climbing_stairs.md: -------------------------------------------------------------------------------- 1 | # Climbing Stairs 2 | 3 | ## Problem Statement 4 | You are climbing a staircase with `n` steps. Each time, you can climb 1 or 2 steps. Return the number of distinct ways to climb to the top. 5 | 6 | **Example**: 7 | - Input: `n = 2` 8 | - Output: `2` 9 | - Explanation: There are two ways: (1,1) and (2). 10 | 11 | **Constraints**: 12 | - `1 <= n <= 45` 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | function climbStairs(n) { 19 | if (n <= 2) return n; 20 | const dp = new Array(n + 1).fill(0); 21 | dp[1] = 1; 22 | dp[2] = 2; 23 | for (let i = 3; i <= n; i++) { 24 | dp[i] = dp[i - 1] + dp[i - 2]; 25 | } 26 | return dp[n]; 27 | } 28 | ``` 29 | 30 | ## Reasoning 31 | - **Approach**: Use dynamic programming to compute the number of ways to reach step `n`. Each step can be reached from step `n-1` (1 step) or `n-2` (2 steps). Thus, `dp[i] = dp[i-1] + dp[i-2]`. Initialize base cases: `dp[1] = 1`, `dp[2] = 2`. 32 | - **Why DP?**: Avoids redundant recursive calls by storing intermediate results, similar to Fibonacci. 33 | - **Edge Cases**: 34 | - `n = 1`: One way (1 step). 35 | - `n = 2`: Two ways (1+1, 2). 36 | - **Optimizations**: Use array-based DP for clarity; can optimize to O(1) space with two variables. 37 | 38 | ## Complexity Analysis 39 | - **Time Complexity**: O(n), single loop from 3 to n. 40 | - **Space Complexity**: O(n) for the DP array. Can be optimized to O(1) using two variables. 41 | 42 | ## Best Practices 43 | - Use clear variable names (e.g., `dp` for dynamic programming array). 44 | - For Python, use type hints for clarity. 45 | - For JavaScript, use array initialization with `fill`. 46 | - For Java, follow Google Java Style Guide. 47 | - Handle base cases early to avoid unnecessary computation. 48 | 49 | ## Alternative Approaches 50 | - **Optimized Space DP**: Use two variables instead of an array (O(n) time, O(1) space). 51 | - **Recursion with Memoization**: Cache results to avoid recomputation (O(n) time, O(n) space). Less efficient than iterative. 52 | - **Math (Fibonacci)**: Direct formula for nth Fibonacci (O(log n) time with matrix exponentiation). Overkill for this problem. -------------------------------------------------------------------------------- /Numpy/Easy/element_wise_multiplication.md: -------------------------------------------------------------------------------- 1 | # Element-Wise Multiplication 2 | 3 | ## Problem Statement 4 | Write a NumPy program to perform element-wise multiplication of two 1D arrays. 5 | 6 | **Input**: 7 | - `arr1`: 1D array of numbers (e.g., `[1, 2, 3]`) 8 | - `arr2`: 1D array of numbers (e.g., `[4, 5, 6]`) 9 | 10 | **Output**: 11 | - 1D array of element-wise products (e.g., `[4, 10, 18]`) 12 | 13 | **Constraints**: 14 | - `1 <= len(arr1) = len(arr2) <= 10^5` 15 | - `-10^5 <= arr1[i], arr2[i] <= 10^5` 16 | 17 | ## Solution 18 | ```python 19 | import numpy as np 20 | 21 | def element_wise_multiplication(arr1: list, arr2: list) -> np.ndarray: 22 | # Convert to numpy arrays and multiply 23 | return np.array(arr1) * np.array(arr2) 24 | ``` 25 | 26 | ## Reasoning 27 | - **Approach**: Convert input lists to NumPy arrays. Use NumPy’s element-wise multiplication (`*`) operator. Return the result. 28 | - **Why NumPy multiplication?**: Vectorized operation is faster than Python loops. 29 | - **Edge Cases**: 30 | - Same length: Ensured by constraints. 31 | - Zero elements: Returns element-wise product (e.g., `[0, 0]`). 32 | - Large values: NumPy handles with float64 precision. 33 | - **Optimizations**: `np.array` multiplication is C-based and vectorized. 34 | 35 | ## Performance Analysis 36 | - **Time Complexity**: O(n), where n is the array length, for element-wise multiplication. 37 | - **Space Complexity**: O(n) for the output array. 38 | - **NumPy Efficiency**: Uses optimized C operations for fast computation. 39 | 40 | ## Best Practices 41 | - Use NumPy’s `*` for element-wise operations. 42 | - Ensure input arrays have the same shape. 43 | - Follow PEP 8 for Python code style. 44 | 45 | ## Alternative Approaches 46 | - **Python List Comprehension**: Manual multiplication (O(n), slower). 47 | ```python 48 | def element_wise_multiplication(arr1: list, arr2: list) -> list: 49 | return [a * b for a, b in zip(arr1, arr2)] 50 | ``` 51 | - **np.multiply**: Explicit function call (O(n), same performance). 52 | ```python 53 | import numpy as np 54 | def element_wise_multiplication(arr1: list, arr2: list) -> np.ndarray: 55 | return np.multiply(np.array(arr1), np.array(arr2)) 56 | ``` -------------------------------------------------------------------------------- /JavaScript/Arrays/Easy/move_zeroes.md: -------------------------------------------------------------------------------- 1 | # Move Zeroes 2 | 3 | ## Problem Statement 4 | Given an integer array `nums`, move all `0`’s to the end of the array while maintaining the relative order of non-zero elements. The operation must be done in-place. 5 | 6 | **Example**: 7 | - Input: `nums = [0,1,0,3,12]` 8 | - Output: `[1,3,12,0,0]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 10^4` 12 | - `-2^31 <= nums[i] <= 2^31 - 1` 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | function moveZeroes(nums) { 19 | let nonZeroPos = 0; 20 | for (let i = 0; i < nums.length; i++) { 21 | if (nums[i] !== 0) { 22 | [nums[nonZeroPos], nums[i]] = [nums[i], nums[nonZeroPos]]; 23 | nonZeroPos++; 24 | } 25 | } 26 | } 27 | ``` 28 | 29 | ## Reasoning 30 | - **Approach**: Use two pointers. Move all non-zero elements to the front by swapping with the `non_zero_pos` index, incrementing it each time. Zeros naturally shift to the end as non-zero elements are placed earlier. 31 | - **Why Two Pointers?**: This ensures in-place operation and maintains relative order without extra space. 32 | - **Edge Cases**: 33 | - All zeros or no zeros: Works correctly without special handling. 34 | - Single element: No change needed. 35 | - **Optimizations**: Single pass to move non-zeros; no need to explicitly set zeros at the end since swaps handle it. 36 | 37 | ## Complexity Analysis 38 | - **Time Complexity**: O(n), where n is the length of `nums`. Single pass through the array. 39 | - **Space Complexity**: O(1), as operations are in-place. 40 | 41 | ## Best Practices 42 | - Use descriptive variable names (e.g., `non_zero_pos`). 43 | - For Python, use type hints and ensure in-place modification. 44 | - For JavaScript, use array destructuring for clean swaps. 45 | - For Java, use explicit temporary variables for swaps and follow Google Java Style Guide. 46 | - Avoid unnecessary passes or extra arrays. 47 | 48 | ## Alternative Approaches 49 | - **Two Passes**: Move non-zeros to the front, then fill the rest with zeros (O(n) time, O(1) space). Less efficient due to extra pass. 50 | - **Extra Array**: Copy non-zeros to a new array, then zeros (O(n) time, O(n) space). Not in-place. -------------------------------------------------------------------------------- /Python/Sorting_Searching/Easy/valid_anagram.md: -------------------------------------------------------------------------------- 1 | # Valid Anagram 2 | 3 | ## Problem Statement 4 | Given two strings `s` and `t`, return `true` if `t` is an anagram of `s`, and `false` otherwise. An anagram is a word formed by rearranging the letters of another. 5 | 6 | **Example**: 7 | - Input: `s = "anagram", t = "nagaram"` 8 | - Output: `true` 9 | 10 | **Constraints**: 11 | - `1 <= s.length, t.length <= 5 * 10^4` 12 | - `s` and `t` consist of lowercase English letters. 13 | 14 | ## Solution 15 | 16 | ### Python 17 | ```python 18 | def isAnagram(s: str, t: str) -> bool: 19 | if len(s) != len(t): 20 | return False 21 | 22 | count = [0] * 26 23 | for c1, c2 in zip(s, t): 24 | count[ord(c1) - ord('a')] += 1 25 | count[ord(c2) - ord('a')] -= 1 26 | 27 | return all(x == 0 for x in count) 28 | ``` 29 | 30 | ## Reasoning 31 | - **Approach**: Use a frequency array to count character occurrences in `s` and `t`. Increment for `s` characters, decrement for `t` characters. If all counts are zero, the strings are anagrams. Check lengths first to avoid unnecessary processing. 32 | - **Why Frequency Array?**: Efficiently tracks character counts in O(n) time with constant space for lowercase letters. 33 | - **Edge Cases**: 34 | - Different lengths: Return false. 35 | - Empty strings: Return true (if both empty). 36 | - Same characters, different counts: Return false. 37 | - **Optimizations**: Single pass over strings; use fixed-size array for 26 letters. 38 | 39 | ## Complexity Analysis 40 | - **Time Complexity**: O(n), where n is the length of `s` or `t`, as we process each character once. 41 | - **Space Complexity**: O(1), as the frequency array is fixed at 26 elements. 42 | 43 | ## Best Practices 44 | - Use clear variable names (e.g., `count`). 45 | - For Python, use type hints and `zip` for iteration. 46 | - For JavaScript, use `charCodeAt` for character indexing. 47 | - For Java, follow Google Java Style Guide. 48 | - Check length early to optimize. 49 | 50 | ## Alternative Approaches 51 | - **Sorting**: Sort both strings and compare (O(n log n) time). Less efficient. 52 | - **Hash Map**: Use a map to count characters (O(n) time, O(n) space). Less space-efficient for fixed alphabet. -------------------------------------------------------------------------------- /Java/Trees/Easy/same_tree.md: -------------------------------------------------------------------------------- 1 | # Same Tree 2 | 3 | ## Problem Statement 4 | Given the roots of two binary trees `p` and `q`, 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. 5 | 6 | **Example**: 7 | - Input: `p = [1,2,3], q = [1,2,3]` 8 | - Output: `true` 9 | 10 | **Constraints**: 11 | - The number of nodes in both trees is in the range `[0, 100]`. 12 | - `-10^4 <= Node.val <= 10^4` 13 | 14 | ## Solution 15 | 16 | ### Java 17 | ```java 18 | class Solution { 19 | public boolean isSameTree(TreeNode p, TreeNode q) { 20 | if (p == null && q == null) return true; 21 | if (p == null || q == null) return false; 22 | return (p.val == q.val && 23 | isSameTree(p.left, q.left) && 24 | isSameTree(p.right, q.right)); 25 | } 26 | } 27 | ``` 28 | 29 | ## Reasoning 30 | - **Approach**: Use recursive comparison. Check if both nodes are null (same), one is null (different), or values differ. Recurse on left and right subtrees. 31 | - **Why Recursive?**: Tree comparison decomposes into checking corresponding nodes and subtrees, making recursion natural and concise. 32 | - **Edge Cases**: 33 | - Both empty: Return true. 34 | - One empty: Return false. 35 | - Single node: Compare values. 36 | - **Optimizations**: Recursive solution is minimal; iterative possible but not simpler. 37 | 38 | ## Complexity Analysis 39 | - **Time Complexity**: O(n), where n is the minimum number of nodes in `p` or `q`, as each node is visited once. 40 | - **Space Complexity**: O(h), where h is the height of the smaller tree, due to the recursion stack (O(n) in worst case for skewed tree). 41 | 42 | ## Best Practices 43 | - Use clear variable names (e.g., `p`, `q`). 44 | - For Python, use type hints. 45 | - For JavaScript, use strict equality (`===`). 46 | - For Java, follow Google Java Style Guide. 47 | - Keep comparison logic concise. 48 | 49 | ## Alternative Approaches 50 | - **Iterative BFS**: Use a queue to compare nodes level-by-level (O(n) time, O(w) space, where w is max width). More complex. 51 | - **Iterative DFS**: Use a stack to compare nodes (O(n) time, O(h) space). Similar complexity but less intuitive. -------------------------------------------------------------------------------- /Python/Backtracking/Easy/combinations.md: -------------------------------------------------------------------------------- 1 | # Combinations 2 | 3 | ## Problem Statement 4 | Given two integers `n` and `k`, return all possible combinations of `k` numbers chosen from the range `[1, n]`. You may return the answer in any order. 5 | 6 | **Example**: 7 | - Input: `n = 4, k = 2` 8 | - Output: `[[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]` 9 | 10 | **Constraints**: 11 | - `1 <= n <= 20` 12 | - `1 <= k <= n` 13 | 14 | ## Solution 15 | 16 | ### Python 17 | ```python 18 | def combine(n: int, k: int) -> list[list[int]]: 19 | result = [] 20 | 21 | def backtrack(start: int, current: list[int]) -> None: 22 | if len(current) == k: 23 | result.append(current[:]) 24 | return 25 | for i in range(start, n + 1): 26 | current.append(i) 27 | backtrack(i + 1, current) 28 | current.pop() 29 | 30 | backtrack(1, []) 31 | return result 32 | ``` 33 | 34 | ## Reasoning 35 | - **Approach**: Use backtracking to build combinations. Start from 1 and add numbers up to `n`, ensuring each combination has `k` numbers. Use a start index to avoid duplicates and maintain order. 36 | - **Why Backtracking?**: Systematically generates all valid combinations while pruning invalid branches. 37 | - **Edge Cases**: 38 | - `k = 0`: Return empty list of lists. 39 | - `k = n`: Return single combination of all numbers. 40 | - **Optimizations**: Copy current list to result to avoid reference issues; use start index to ensure ascending order. 41 | 42 | ## Complexity Analysis 43 | - **Time Complexity**: O(n choose k) = O(n! / (k!(n-k)!)), the number of k-combinations. 44 | - **Space Complexity**: O(k) for the recursion stack, plus O(n choose k) for the output. 45 | 46 | ## Best Practices 47 | - Use clear variable names (e.g., `start`, `current`). 48 | - For Python, use type hints and list copying. 49 | - For JavaScript, use spread operator for copying. 50 | - For Java, use `ArrayList` and follow Google Java Style Guide. 51 | - Use start index to avoid duplicate combinations. 52 | 53 | ## Alternative Approaches 54 | - **Iterative**: Use a loop to generate combinations (same complexity). More complex to implement. 55 | - **Math-Based**: Use combinatorial formulas (complex to code). -------------------------------------------------------------------------------- /Python/Linked_Lists/Medium/swap_nodes_in_pairs.md: -------------------------------------------------------------------------------- 1 | # Swap Nodes in Pairs 2 | 3 | ## Problem Statement 4 | Given a linked list, swap every two adjacent nodes and return its head. You must solve the problem without modifying the values in the nodes (only nodes themselves may be changed). 5 | 6 | **Example**: 7 | - Input: `head = [1,2,3,4]` 8 | - Output: `[2,1,4,3]` 9 | 10 | **Constraints**: 11 | - The number of nodes in the list is in the range `[0, 100]`. 12 | - `0 <= Node.val <= 100` 13 | 14 | ## Solution 15 | 16 | ### Python 17 | ```python 18 | class ListNode: 19 | def __init__(self, val=0, next=None): 20 | self.val = val 21 | self.next = next 22 | 23 | def swapPairs(head: ListNode) -> ListNode: 24 | if not head or not head.next: 25 | return head 26 | 27 | next_node = head.next 28 | head.next = swapPairs(next_node.next) 29 | next_node.next = head 30 | return next_node 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use recursion to swap pairs. For each pair, swap the current node with the next, recursively swap the rest of the list, and connect the swapped pair. Base case: return if list is empty or has one node. 35 | - **Why Recursive?**: Simplifies swapping logic by handling pairs recursively, ensuring clean pointer updates. 36 | - **Edge Cases**: 37 | - Empty list or single node: Return as is. 38 | - Odd number of nodes: Last node remains unswapped. 39 | - **Optimizations**: Recursive approach is concise; no extra space except recursion stack. 40 | 41 | ## Complexity Analysis 42 | - **Time Complexity**: O(n), where n is the number of nodes, as we process each node once. 43 | - **Space Complexity**: O(n) due to the recursion stack for n/2 recursive calls. 44 | 45 | ## Best Practices 46 | - Use clear variable names (e.g., `nextNode`). 47 | - For Python, use type hints for clarity. 48 | - For JavaScript, use concise null checks. 49 | - For Java, follow Google Java Style Guide. 50 | - Handle base cases early. 51 | 52 | ## Alternative Approaches 53 | - **Iterative**: Use pointers to swap pairs in-place (O(n) time, O(1) space). More complex but space-efficient. 54 | - **Dummy Node Iterative**: Use a dummy node to simplify iterative swapping (O(n) time, O(1) space). Slightly clearer. -------------------------------------------------------------------------------- /JavaScript/Dynamic_Programming/Easy/min_cost_climbing_stairs.md: -------------------------------------------------------------------------------- 1 | # Min Cost Climbing Stairs 2 | 3 | ## Problem Statement 4 | You are given an array `cost` where `cost[i]` is the cost of climbing the ith step. You can climb 1 or 2 steps at a time. You can start from step 0 or 1. Return the minimum cost to reach the top (beyond the last step). 5 | 6 | **Example**: 7 | - Input: `cost = [10,15,20]` 8 | - Output: `15` 9 | - Explanation: Start at step 1 (15), then reach the top (0 cost). 10 | 11 | **Constraints**: 12 | - `2 <= cost.length <= 1000` 13 | - `0 <= cost[i] <= 999` 14 | 15 | ## Solution 16 | 17 | ### JavaScript 18 | ```javascript 19 | function minCostClimbingStairs(cost) { 20 | const n = cost.length; 21 | const dp = new Array(n + 1).fill(0); 22 | for (let i = 2; i <= n; i++) { 23 | dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]); 24 | } 25 | return dp[n]; 26 | } 27 | ``` 28 | 29 | ## Reasoning 30 | - **Approach**: Use dynamic programming to compute the minimum cost to reach each step. For step `i`, take the minimum of coming from `i-1` or `i-2`: `dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])`. The top is beyond the last step, so return `dp[n]`. 31 | - **Why DP?**: Avoids recomputing costs by storing minimum costs for each step. 32 | - **Edge Cases**: 33 | - `n = 2`: Return minimum of `cost[0]` or `cost[1]`. 34 | - **Optimizations**: Use array-based DP; can optimize to O(1) space with two variables. 35 | 36 | ## Complexity Analysis 37 | - **Time Complexity**: O(n), single loop from 2 to n. 38 | - **Space Complexity**: O(n) for the DP array. Can be optimized to O(1) using two variables. 39 | 40 | ## Best Practices 41 | - Use clear variable names (e.g., `dp` for dynamic programming array). 42 | - For Python, use type hints for clarity. 43 | - For JavaScript, use array initialization with `fill`. 44 | - For Java, follow Google Java Style Guide. 45 | - Initialize `dp[0]` and `dp[1]` as 0 since starting costs are free. 46 | 47 | ## Alternative Approaches 48 | - **Optimized Space DP**: Use two variables (O(n) time, O(1) space). 49 | - **Recursion with Memoization**: Cache results (O(n) time, O(n) space). Less efficient than iterative. 50 | - **Brute Force**: Try all paths (O(2^n) time). Too slow. -------------------------------------------------------------------------------- /Java/Dynamic_Programming/Easy/climbing_stairs.md: -------------------------------------------------------------------------------- 1 | # Climbing Stairs 2 | 3 | ## Problem Statement 4 | You are climbing a staircase with `n` steps. Each time, you can climb 1 or 2 steps. Return the number of distinct ways to climb to the top. 5 | 6 | **Example**: 7 | - Input: `n = 2` 8 | - Output: `2` 9 | - Explanation: There are two ways: (1,1) and (2). 10 | 11 | **Constraints**: 12 | - `1 <= n <= 45` 13 | 14 | ## Solution 15 | 16 | ### Java 17 | ```java 18 | class Solution { 19 | public int climbStairs(int n) { 20 | if (n <= 2) return n; 21 | int[] dp = new int[n + 1]; 22 | dp[1] = 1; 23 | dp[2] = 2; 24 | for (int i = 3; i <= n; i++) { 25 | dp[i] = dp[i - 1] + dp[i - 2]; 26 | } 27 | return dp[n]; 28 | } 29 | } 30 | ``` 31 | 32 | ## Reasoning 33 | - **Approach**: Use dynamic programming to compute the number of ways to reach step `n`. Each step can be reached from step `n-1` (1 step) or `n-2` (2 steps). Thus, `dp[i] = dp[i-1] + dp[i-2]`. Initialize base cases: `dp[1] = 1`, `dp[2] = 2`. 34 | - **Why DP?**: Avoids redundant recursive calls by storing intermediate results, similar to Fibonacci. 35 | - **Edge Cases**: 36 | - `n = 1`: One way (1 step). 37 | - `n = 2`: Two ways (1+1, 2). 38 | - **Optimizations**: Use array-based DP for clarity; can optimize to O(1) space with two variables. 39 | 40 | ## Complexity Analysis 41 | - **Time Complexity**: O(n), single loop from 3 to n. 42 | - **Space Complexity**: O(n) for the DP array. Can be optimized to O(1) using two variables. 43 | 44 | ## Best Practices 45 | - Use clear variable names (e.g., `dp` for dynamic programming array). 46 | - For Python, use type hints for clarity. 47 | - For JavaScript, use array initialization with `fill`. 48 | - For Java, follow Google Java Style Guide. 49 | - Handle base cases early to avoid unnecessary computation. 50 | 51 | ## Alternative Approaches 52 | - **Optimized Space DP**: Use two variables instead of an array (O(n) time, O(1) space). 53 | - **Recursion with Memoization**: Cache results to avoid recomputation (O(n) time, O(n) space). Less efficient than iterative. 54 | - **Math (Fibonacci)**: Direct formula for nth Fibonacci (O(log n) time with matrix exponentiation). Overkill for this problem. -------------------------------------------------------------------------------- /Python/Backtracking/Easy/Easy_subsets.md: -------------------------------------------------------------------------------- 1 | # Subsets 2 | 3 | ## Problem Statement 4 | Given an integer array `nums` of unique elements, return all possible subsets (the power set). The solution set must not contain duplicate subsets. Return the answer in any order. 5 | 6 | **Example**: 7 | - Input: `nums = [1,2,3]` 8 | - Output: `[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 10` 12 | - `-10 <= nums[i] <= 10` 13 | - All elements in `nums` are unique. 14 | 15 | ## Solution 16 | 17 | ### Python 18 | ```python 19 | def subsets(nums: list[int]) -> list[list[int]]: 20 | result = [] 21 | 22 | def backtrack(index: int, current: list[int]) -> None: 23 | result.append(current[:]) 24 | for i in range(index, len(nums)): 25 | current.append(nums[i]) 26 | backtrack(i + 1, current) 27 | current.pop() 28 | 29 | backtrack(0, []) 30 | return result 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use backtracking to generate all subsets. At each index, include or exclude the current number, adding the current subset to the result at each step. Use an index to avoid duplicates. 35 | - **Why Backtracking?**: Efficiently explores all possible subsets by making choices at each step. 36 | - **Edge Cases**: 37 | - Empty array: Return `[[]]`. 38 | - Single element: Return `[[], [element]]`. 39 | - **Optimizations**: Add subset at each step; copy current list to avoid reference issues. 40 | 41 | ## Complexity Analysis 42 | - **Time Complexity**: O(2^n), where n is the length of `nums`, as there are 2^n possible subsets. 43 | - **Space Complexity**: O(n) for the recursion stack, plus O(2^n) for the output. 44 | 45 | ## Best Practices 46 | - Use clear variable names (e.g., `index`, `current`). 47 | - For Python, use type hints and list copying. 48 | - For JavaScript, use spread operator for copying. 49 | - For Java, use `ArrayList` and follow Google Java Style Guide. 50 | - Include empty subset in results. 51 | 52 | ## Alternative Approaches 53 | - **Bit Manipulation**: Use binary numbers to represent subsets (O(2^n) time). Less intuitive. 54 | - **Iterative**: Build subsets by adding each element to existing subsets (same complexity). More complex. -------------------------------------------------------------------------------- /Python/Dynamic_Programming/Easy/climbing_stairs.md: -------------------------------------------------------------------------------- 1 | # Climbing Stairs 2 | 3 | ## Problem Statement 4 | You are climbing a staircase with `n` steps. Each time, you can climb 1 or 2 steps. Return the number of distinct ways to climb to the top. 5 | 6 | **Example**: 7 | - Input: `n = 2` 8 | - Output: `2` 9 | - Explanation: There are two ways: (1,1) and (2). 10 | 11 | **Constraints**: 12 | - `1 <= n <= 45` 13 | 14 | ## Solution 15 | 16 | ### Java 17 | ```java 18 | class Solution { 19 | public int climbStairs(int n) { 20 | if (n <= 2) return n; 21 | int[] dp = new int[n + 1]; 22 | dp[1] = 1; 23 | dp[2] = 2; 24 | for (int i = 3; i <= n; i++) { 25 | dp[i] = dp[i - 1] + dp[i - 2]; 26 | } 27 | return dp[n]; 28 | } 29 | } 30 | ``` 31 | 32 | ## Reasoning 33 | - **Approach**: Use dynamic programming to compute the number of ways to reach step `n`. Each step can be reached from step `n-1` (1 step) or `n-2` (2 steps). Thus, `dp[i] = dp[i-1] + dp[i-2]`. Initialize base cases: `dp[1] = 1`, `dp[2] = 2`. 34 | - **Why DP?**: Avoids redundant recursive calls by storing intermediate results, similar to Fibonacci. 35 | - **Edge Cases**: 36 | - `n = 1`: One way (1 step). 37 | - `n = 2`: Two ways (1+1, 2). 38 | - **Optimizations**: Use array-based DP for clarity; can optimize to O(1) space with two variables. 39 | 40 | ## Complexity Analysis 41 | - **Time Complexity**: O(n), single loop from 3 to n. 42 | - **Space Complexity**: O(n) for the DP array. Can be optimized to O(1) using two variables. 43 | 44 | ## Best Practices 45 | - Use clear variable names (e.g., `dp` for dynamic programming array). 46 | - For Python, use type hints for clarity. 47 | - For JavaScript, use array initialization with `fill`. 48 | - For Java, follow Google Java Style Guide. 49 | - Handle base cases early to avoid unnecessary computation. 50 | 51 | ## Alternative Approaches 52 | - **Optimized Space DP**: Use two variables instead of an array (O(n) time, O(1) space). 53 | - **Recursion with Memoization**: Cache results to avoid recomputation (O(n) time, O(n) space). Less efficient than iterative. 54 | - **Math (Fibonacci)**: Direct formula for nth Fibonacci (O(log n) time with matrix exponentiation). Overkill for this problem. -------------------------------------------------------------------------------- /Python/Trees/Easy/same_tree.md: -------------------------------------------------------------------------------- 1 | # Same Tree 2 | 3 | ## Problem Statement 4 | Given the roots of two binary trees `p` and `q`, 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. 5 | 6 | **Example**: 7 | - Input: `p = [1,2,3], q = [1,2,3]` 8 | - Output: `true` 9 | 10 | **Constraints**: 11 | - The number of nodes in both trees is in the range `[0, 100]`. 12 | - `-10^4 <= Node.val <= 10^4` 13 | 14 | ## Solution 15 | 16 | ### Python 17 | ```python 18 | class Solution: 19 | def isSameTree(self, p: TreeNode, q: TreeNode) -> bool: 20 | if not p and not q: 21 | return True 22 | if not p or not q: 23 | return False 24 | return (p.val == q.val and 25 | self.isSameTree(p.left, q.left) and 26 | self.isSameTree(p.right, q.right)) 27 | ``` 28 | 29 | ## Reasoning 30 | - **Approach**: Use recursive comparison. Check if both nodes are null (same), one is null (different), or values differ. Recurse on left and right subtrees. 31 | - **Why Recursive?**: Tree comparison decomposes into checking corresponding nodes and subtrees, making recursion natural and concise. 32 | - **Edge Cases**: 33 | - Both empty: Return true. 34 | - One empty: Return false. 35 | - Single node: Compare values. 36 | - **Optimizations**: Recursive solution is minimal; iterative possible but not simpler. 37 | 38 | ## Complexity Analysis 39 | - **Time Complexity**: O(n), where n is the minimum number of nodes in `p` or `q`, as each node is visited once. 40 | - **Space Complexity**: O(h), where h is the height of the smaller tree, due to the recursion stack (O(n) in worst case for skewed tree). 41 | 42 | ## Best Practices 43 | - Use clear variable names (e.g., `p`, `q`). 44 | - For Python, use type hints. 45 | - For JavaScript, use strict equality (`===`). 46 | - For Java, follow Google Java Style Guide. 47 | - Keep comparison logic concise. 48 | 49 | ## Alternative Approaches 50 | - **Iterative BFS**: Use a queue to compare nodes level-by-level (O(n) time, O(w) space, where w is max width). More complex. 51 | - **Iterative DFS**: Use a stack to compare nodes (O(n) time, O(h) space). Similar complexity but less intuitive. -------------------------------------------------------------------------------- /JavaScript/Linked_Lists/Medium/swap_nodes_in_pairs.md: -------------------------------------------------------------------------------- 1 | # Swap Nodes in Pairs 2 | 3 | ## Problem Statement 4 | Given a linked list, swap every two adjacent nodes and return its head. You must solve the problem without modifying the values in the nodes (only nodes themselves may be changed). 5 | 6 | **Example**: 7 | - Input: `head = [1,2,3,4]` 8 | - Output: `[2,1,4,3]` 9 | 10 | **Constraints**: 11 | - The number of nodes in the list is in the range `[0, 100]`. 12 | - `0 <= Node.val <= 100` 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | function ListNode(val, next) { 19 | this.val = (val === undefined ? 0 : val); 20 | this.next = (next === undefined ? null : next); 21 | } 22 | 23 | function swapPairs(head) { 24 | if (!head || !head.next) return head; 25 | 26 | const nextNode = head.next; 27 | head.next = swapPairs(nextNode.next); 28 | nextNode.next = head; 29 | return nextNode; 30 | } 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use recursion to swap pairs. For each pair, swap the current node with the next, recursively swap the rest of the list, and connect the swapped pair. Base case: return if list is empty or has one node. 35 | - **Why Recursive?**: Simplifies swapping logic by handling pairs recursively, ensuring clean pointer updates. 36 | - **Edge Cases**: 37 | - Empty list or single node: Return as is. 38 | - Odd number of nodes: Last node remains unswapped. 39 | - **Optimizations**: Recursive approach is concise; no extra space except recursion stack. 40 | 41 | ## Complexity Analysis 42 | - **Time Complexity**: O(n), where n is the number of nodes, as we process each node once. 43 | - **Space Complexity**: O(n) due to the recursion stack for n/2 recursive calls. 44 | 45 | ## Best Practices 46 | - Use clear variable names (e.g., `nextNode`). 47 | - For Python, use type hints for clarity. 48 | - For JavaScript, use concise null checks. 49 | - For Java, follow Google Java Style Guide. 50 | - Handle base cases early. 51 | 52 | ## Alternative Approaches 53 | - **Iterative**: Use pointers to swap pairs in-place (O(n) time, O(1) space). More complex but space-efficient. 54 | - **Dummy Node Iterative**: Use a dummy node to simplify iterative swapping (O(n) time, O(1) space). Slightly clearer. -------------------------------------------------------------------------------- /Python/Arrays/Easy/contains_duplicate.md: -------------------------------------------------------------------------------- 1 | # Contains Duplicate 2 | 3 | ## Problem Statement 4 | Given an integer array `nums`, return `true` if any value appears at least twice in the array, and `false` if every element is distinct. 5 | 6 | **Example**: 7 | - Input: `nums = [1,2,3,1]` 8 | - Output: `true` 9 | - Explanation: The element `1` appears twice. 10 | 11 | **Constraints**: 12 | - `1 <= nums.length <= 10^5` 13 | - `-10^9 <= nums[i] <= 10^9` 14 | 15 | ## Solution 16 | 17 | ### Python 18 | ```python 19 | def containsDuplicate(nums: list[int]) -> bool: 20 | return len(nums) != len(set(nums)) 21 | ``` 22 | 23 | ## Reasoning 24 | - **Approach**: Use a set to check for duplicates. In Python and JavaScript, convert the array to a set and compare sizes. In Java, add elements to a set and check if any addition fails (indicating a duplicate). 25 | - **Why Set?**: Sets store unique elements, making duplicate detection efficient. Comparing set size to array length is a concise way to check for duplicates. 26 | - **Edge Cases**: 27 | - Empty array: Returns `false` (no duplicates). 28 | - Single element: Returns `false` (no duplicates possible). 29 | - Large arrays: Set operations remain efficient due to O(1) average-time lookups. 30 | - **Optimizations**: The Python/JavaScript solutions are concise and leverage built-in set conversion. The Java solution stops early upon finding a duplicate. 31 | 32 | ## Complexity Analysis 33 | - **Time Complexity**: O(n), where n is the length of `nums`. Set conversion or iteration takes linear time. 34 | - **Space Complexity**: O(n) to store the set of unique elements. 35 | 36 | ## Best Practices 37 | - Use clear variable names (e.g., `set` for the data structure). 38 | - For Python, include type hints for clarity and pylint compliance. 39 | - For JavaScript, use `Set` for efficient unique value storage. 40 | - For Java, use `HashSet` and follow Google Java Style Guide. 41 | - Prefer concise solutions when they maintain readability and performance. 42 | 43 | ## Alternative Approaches 44 | - **Sorting**: Sort the array and check adjacent elements for duplicates (O(n log n) time, O(1) space if in-place). 45 | - **Brute Force**: Compare each element with every other element (O(n²) time, O(1) space). Inefficient for large arrays. -------------------------------------------------------------------------------- /Python/Trees/Easy/binary_tree_inorder_traversal.md: -------------------------------------------------------------------------------- 1 | # Binary Tree Inorder Traversal 2 | 3 | ## Problem Statement 4 | Given the root of a binary tree, return the inorder traversal of its nodes' values (left, root, right). 5 | 6 | **Example**: 7 | - Input: `root = [1,null,2,3]` 8 | - Output: `[1,3,2]` 9 | 10 | **Constraints**: 11 | - The number of nodes is in the range `[0, 100]`. 12 | - `-100 <= Node.val <= 100` 13 | 14 | ## Solution 15 | 16 | ### Python 17 | ```python 18 | class Solution: 19 | def inorderTraversal(self, root: TreeNode) -> list[int]: 20 | result = [] 21 | def inorder(node): 22 | if not node: 23 | return 24 | inorder(node.left) 25 | result.append(node.val) 26 | inorder(node.right) 27 | inorder(root) 28 | return result 29 | ``` 30 | 31 | ## Reasoning 32 | - **Approach**: Use recursive inorder traversal. Visit the left subtree, append the current node’s value, then visit the right subtree. Store results in a list. 33 | - **Why Recursive?**: Inorder traversal naturally follows a recursive pattern, ensuring correct order (left, root, right) with minimal code. 34 | - **Edge Cases**: 35 | - Empty tree: Return empty list. 36 | - Single node: Return [node.val]. 37 | - Skewed tree: Works like a linked list. 38 | - **Optimizations**: Recursive solution is clean and leverages call stack; iterative solution possible but more complex. 39 | 40 | ## Complexity Analysis 41 | - **Time Complexity**: O(n), where n is the number of nodes, as each node is visited once. 42 | - **Space Complexity**: O(h), where h is the height of the tree, due to the recursion stack (O(n) in worst case for skewed tree). 43 | 44 | ## Best Practices 45 | - Use clear variable names (e.g., `result`, `node`). 46 | - For Python, use type hints and helper function. 47 | - For JavaScript, use nested function for recursion. 48 | - For Java, use `List` and follow Google Java Style Guide. 49 | - Keep recursion simple for readability. 50 | 51 | ## Alternative Approaches 52 | - **Iterative**: Use a stack to mimic recursion (O(n) time, O(h) space). More complex but avoids recursion overhead. 53 | - **Morris Traversal**: Threaded binary tree approach (O(n) time, O(1) space). Advanced and less readable. -------------------------------------------------------------------------------- /JavaScript/Sorting_Searching/Easy/valid_anagram.md: -------------------------------------------------------------------------------- 1 | # Valid Anagram 2 | 3 | ## Problem Statement 4 | Given two strings `s` and `t`, return `true` if `t` is an anagram of `s`, and `false` otherwise. An anagram is a word formed by rearranging the letters of another. 5 | 6 | **Example**: 7 | - Input: `s = "anagram", t = "nagaram"` 8 | - Output: `true` 9 | 10 | **Constraints**: 11 | - `1 <= s.length, t.length <= 5 * 10^4` 12 | - `s` and `t` consist of lowercase English letters. 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | function isAnagram(s, t) { 19 | if (s.length !== t.length) return false; 20 | 21 | const count = new Array(26).fill(0); 22 | for (let i = 0; i < s.length; i++) { 23 | count[s.charCodeAt(i) - 97]++; 24 | count[t.charCodeAt(i) - 97]--; 25 | } 26 | 27 | return count.every(x => x === 0); 28 | } 29 | ``` 30 | 31 | ## Reasoning 32 | - **Approach**: Use a frequency array to count character occurrences in `s` and `t`. Increment for `s` characters, decrement for `t` characters. If all counts are zero, the strings are anagrams. Check lengths first to avoid unnecessary processing. 33 | - **Why Frequency Array?**: Efficiently tracks character counts in O(n) time with constant space for lowercase letters. 34 | - **Edge Cases**: 35 | - Different lengths: Return false. 36 | - Empty strings: Return true (if both empty). 37 | - Same characters, different counts: Return false. 38 | - **Optimizations**: Single pass over strings; use fixed-size array for 26 letters. 39 | 40 | ## Complexity Analysis 41 | - **Time Complexity**: O(n), where n is the length of `s` or `t`, as we process each character once. 42 | - **Space Complexity**: O(1), as the frequency array is fixed at 26 elements. 43 | 44 | ## Best Practices 45 | - Use clear variable names (e.g., `count`). 46 | - For Python, use type hints and `zip` for iteration. 47 | - For JavaScript, use `charCodeAt` for character indexing. 48 | - For Java, follow Google Java Style Guide. 49 | - Check length early to optimize. 50 | 51 | ## Alternative Approaches 52 | - **Sorting**: Sort both strings and compare (O(n log n) time). Less efficient. 53 | - **Hash Map**: Use a map to count characters (O(n) time, O(n) space). Less space-efficient for fixed alphabet. -------------------------------------------------------------------------------- /Python/Linked_Lists/Medium/remove_nth_node.md: -------------------------------------------------------------------------------- 1 | # Remove Nth Node From End of List 2 | 3 | ## Problem Statement 4 | Given the head of a linked list, remove the nth node from the end and return the head. 5 | 6 | **Example**: 7 | - Input: `head = [1,2,3,4,5], n = 2` 8 | - Output: `[1,2,3,5]` 9 | 10 | **Constraints**: 11 | - The number of nodes in the list is `sz`. 12 | - `1 <= sz <= 30` 13 | - `0 <= Node.val <= 100` 14 | - `1 <= n <= sz` 15 | 16 | ## Solution 17 | 18 | ### Python 19 | ```python 20 | class ListNode: 21 | def __init__(self, val=0, next=None): 22 | self.val = val 23 | self.next = next 24 | 25 | def removeNthFromEnd(head: ListNode, n: int) -> ListNode: 26 | dummy = ListNode(0, head) 27 | slow = fast = dummy 28 | 29 | for _ in range(n + 1): 30 | fast = fast.next 31 | 32 | while fast: 33 | slow = slow.next 34 | fast = fast.next 35 | 36 | slow.next = slow.next.next 37 | return dummy.next 38 | ``` 39 | 40 | ## Reasoning 41 | - **Approach**: Use two pointers (slow and fast). Move fast n+1 steps ahead, then move both pointers until fast reaches the end. Slow will be just before the node to remove. Adjust the next pointer to skip the nth node. 42 | - **Why Two Pointers?**: Allows finding the nth node from the end in one pass without counting the list length. 43 | - **Edge Cases**: 44 | - Remove head: Use dummy node to simplify. 45 | - Single node: Return null if n=1. 46 | - **Optimizations**: Dummy node handles head removal; single pass for efficiency. 47 | 48 | ## Complexity Analysis 49 | - **Time Complexity**: O(n), where n is the number of nodes, as we traverse the list once. 50 | - **Space Complexity**: O(1), as we only use two pointers and a dummy node. 51 | 52 | ## Best Practices 53 | - Use clear variable names (e.g., `slow`, `fast`). 54 | - For Python, use type hints for clarity. 55 | - For JavaScript, use concise loop constructs. 56 | - For Java, follow Google Java Style Guide. 57 | - Use dummy node to handle edge cases. 58 | 59 | ## Alternative Approaches 60 | - **Two Passes**: Count list length, then traverse to remove node (O(n) time, O(1) space). Less efficient. 61 | - **Stack-Based**: Store nodes in a stack, pop n times (O(n) time, O(n) space). Less space-efficient. -------------------------------------------------------------------------------- /Java/Linked_Lists/Easy/middle_of_linked_list.md: -------------------------------------------------------------------------------- 1 | # Middle of the Linked List 2 | 3 | ## Problem Statement 4 | Given the head of a singly linked list, return the middle node. If there are two middle nodes, return the second one. 5 | 6 | **Example**: 7 | - Input: `head = [1,2,3,4,5]` 8 | - Output: `[3,4,5]` 9 | 10 | **Constraints**: 11 | - The number of nodes in the list is in the range `[1, 100]`. 12 | - `1 <= Node.val <= 100` 13 | 14 | ## Solution 15 | 16 | ### Java 17 | ```java 18 | class ListNode { 19 | int val; 20 | ListNode next; 21 | ListNode(int val) { this.val = val; } 22 | ListNode(int val, ListNode next) { this.val = val; this.next = next; } 23 | } 24 | 25 | class Solution { 26 | public ListNode middleNode(ListNode head) { 27 | ListNode slow = head, fast = head; 28 | while (fast != null && fast.next != null) { 29 | slow = slow.next; 30 | fast = fast.next.next; 31 | } 32 | return slow; 33 | } 34 | } 35 | ``` 36 | 37 | ## Reasoning 38 | - **Approach**: Use the two-pointer technique (slow and fast pointers). Slow moves one step, fast moves two steps. When fast reaches the end, slow is at the middle. For even-length lists, slow lands on the second middle node. 39 | - **Why Two Pointers?**: Finds the middle in one pass without counting nodes, using O(1) space. 40 | - **Edge Cases**: 41 | - Single node: Return the head. 42 | - Even number of nodes: Return the second middle node. 43 | - **Optimizations**: Single pass with two pointers; no extra space needed. 44 | 45 | ## Complexity Analysis 46 | - **Time Complexity**: O(n), where n is the number of nodes, as we traverse the list once. 47 | - **Space Complexity**: O(1), as only two pointers are used. 48 | 49 | ## Best Practices 50 | - Use clear variable names (e.g., `slow`, `fast`). 51 | - For Python, use type hints for clarity. 52 | - For JavaScript, use concise pointer updates. 53 | - For Java, follow Google Java Style Guide. 54 | - Handle null checks in the loop condition. 55 | 56 | ## Alternative Approaches 57 | - **Count and Find**: Count nodes, then traverse to the middle (O(n) time, O(1) space). Two passes, less efficient. 58 | - **Array-Based**: Store nodes in an array and return middle (O(n) time, O(n) space). Less space-efficient. -------------------------------------------------------------------------------- /JavaScript/Trees/Easy/binary_tree_inorder_traversal.md: -------------------------------------------------------------------------------- 1 | # Binary Tree Inorder Traversal 2 | 3 | ## Problem Statement 4 | Given the root of a binary tree, return the inorder traversal of its nodes' values (left, root, right). 5 | 6 | **Example**: 7 | - Input: `root = [1,null,2,3]` 8 | - Output: `[1,3,2]` 9 | 10 | **Constraints**: 11 | - The number of nodes is in the range `[0, 100]`. 12 | - `-100 <= Node.val <= 100` 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | class Solution { 19 | inorderTraversal(root) { 20 | const result = []; 21 | function inorder(node) { 22 | if (!node) return; 23 | inorder(node.left); 24 | result.push(node.val); 25 | inorder(node.right); 26 | } 27 | inorder(root); 28 | return result; 29 | } 30 | } 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use recursive inorder traversal. Visit the left subtree, append the current node’s value, then visit the right subtree. Store results in a list. 35 | - **Why Recursive?**: Inorder traversal naturally follows a recursive pattern, ensuring correct order (left, root, right) with minimal code. 36 | - **Edge Cases**: 37 | - Empty tree: Return empty list. 38 | - Single node: Return [node.val]. 39 | - Skewed tree: Works like a linked list. 40 | - **Optimizations**: Recursive solution is clean and leverages call stack; iterative solution possible but more complex. 41 | 42 | ## Complexity Analysis 43 | - **Time Complexity**: O(n), where n is the number of nodes, as each node is visited once. 44 | - **Space Complexity**: O(h), where h is the height of the tree, due to the recursion stack (O(n) in worst case for skewed tree). 45 | 46 | ## Best Practices 47 | - Use clear variable names (e.g., `result`, `node`). 48 | - For Python, use type hints and helper function. 49 | - For JavaScript, use nested function for recursion. 50 | - For Java, use `List` and follow Google Java Style Guide. 51 | - Keep recursion simple for readability. 52 | 53 | ## Alternative Approaches 54 | - **Iterative**: Use a stack to mimic recursion (O(n) time, O(h) space). More complex but avoids recursion overhead. 55 | - **Morris Traversal**: Threaded binary tree approach (O(n) time, O(1) space). Advanced and less readable. -------------------------------------------------------------------------------- /Python/Arrays/Easy/single_number.md: -------------------------------------------------------------------------------- 1 | # Single Number 2 | 3 | ## Problem Statement 4 | Given a non-empty array of integers `nums`, every element appears twice except for one. Find that single one. You must implement a solution with a linear runtime complexity and use only constant extra space. 5 | 6 | **Example**: 7 | - Input: `nums = [2,2,1]` 8 | - Output: `1` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 3 * 10^4` 12 | - `-3 * 10^4 <= nums[i] <= 3 * 10^4` 13 | - Each element appears twice except for one element which appears once. 14 | 15 | ## Solution 16 | 17 | ### Python 18 | ```python 19 | def singleNumber(nums: list[int]) -> int: 20 | result = 0 21 | for num in nums: 22 | result ^= num 23 | return result 24 | ``` 25 | 26 | ## Reasoning 27 | - **Approach**: Use XOR bitwise operation. XOR of a number with itself is 0, and XOR of a number with 0 is the number itself. Since all numbers except one appear twice, XORing all elements cancels out pairs, leaving the single number. 28 | - **Why XOR?**: It meets the requirement for O(n) time and O(1) space, as it processes each element once without extra storage. 29 | - **Edge Cases**: 30 | - Single element: Returns that element. 31 | - All pairs except one: XOR correctly isolates the single number. 32 | - **Optimizations**: Single pass with a single variable; no additional data structures needed. 33 | 34 | ## Complexity Analysis 35 | - **Time Complexity**: O(n), where n is the length of `nums`. Single pass through the array. 36 | - **Space Complexity**: O(1), as only one variable is used. 37 | 38 | ## Best Practices 39 | - Use clear variable names (e.g., `result` for XOR accumulator). 40 | - For Python, include type hints for clarity. 41 | - For JavaScript, use `for...of` for readable iteration. 42 | - For Java, follow Google Java Style Guide. 43 | - Leverage XOR’s properties for elegant, efficient solutions. 44 | 45 | ## Alternative Approaches 46 | - **Hash Set**: Store elements in a set, removing duplicates (O(n) time, O(n) space). Violates constant space requirement. 47 | - **Hash Map**: Count frequencies and find the element with count 1 (O(n) time, O(n) space). Also violates space constraint. 48 | - **Sorting**: Sort and find the unpaired element (O(n log n) time, O(1) space). Slower than XOR. -------------------------------------------------------------------------------- /JavaScript/Arrays/Easy/contains_duplicate.md: -------------------------------------------------------------------------------- 1 | # Contains Duplicate 2 | 3 | ## Problem Statement 4 | Given an integer array `nums`, return `true` if any value appears at least twice in the array, and `false` if every element is distinct. 5 | 6 | **Example**: 7 | - Input: `nums = [1,2,3,1]` 8 | - Output: `true` 9 | - Explanation: The element `1` appears twice. 10 | 11 | **Constraints**: 12 | - `1 <= nums.length <= 10^5` 13 | - `-10^9 <= nums[i] <= 10^9` 14 | 15 | ## Solution 16 | 17 | ### JavaScript 18 | ```javascript 19 | function containsDuplicate(nums) { 20 | return new Set(nums).size !== nums.length; 21 | } 22 | ``` 23 | 24 | ## Reasoning 25 | - **Approach**: Use a set to check for duplicates. In Python and JavaScript, convert the array to a set and compare sizes. In Java, add elements to a set and check if any addition fails (indicating a duplicate). 26 | - **Why Set?**: Sets store unique elements, making duplicate detection efficient. Comparing set size to array length is a concise way to check for duplicates. 27 | - **Edge Cases**: 28 | - Empty array: Returns `false` (no duplicates). 29 | - Single element: Returns `false` (no duplicates possible). 30 | - Large arrays: Set operations remain efficient due to O(1) average-time lookups. 31 | - **Optimizations**: The Python/JavaScript solutions are concise and leverage built-in set conversion. The Java solution stops early upon finding a duplicate. 32 | 33 | ## Complexity Analysis 34 | - **Time Complexity**: O(n), where n is the length of `nums`. Set conversion or iteration takes linear time. 35 | - **Space Complexity**: O(n) to store the set of unique elements. 36 | 37 | ## Best Practices 38 | - Use clear variable names (e.g., `set` for the data structure). 39 | - For Python, include type hints for clarity and pylint compliance. 40 | - For JavaScript, use `Set` for efficient unique value storage. 41 | - For Java, use `HashSet` and follow Google Java Style Guide. 42 | - Prefer concise solutions when they maintain readability and performance. 43 | 44 | ## Alternative Approaches 45 | - **Sorting**: Sort the array and check adjacent elements for duplicates (O(n log n) time, O(1) space if in-place). 46 | - **Brute Force**: Compare each element with every other element (O(n²) time, O(1) space). Inefficient for large arrays. -------------------------------------------------------------------------------- /JavaScript/Backtracking/Easy/Easy_subsets.md: -------------------------------------------------------------------------------- 1 | # Subsets 2 | 3 | ## Problem Statement 4 | Given an integer array `nums` of unique elements, return all possible subsets (the power set). The solution set must not contain duplicate subsets. Return the answer in any order. 5 | 6 | **Example**: 7 | - Input: `nums = [1,2,3]` 8 | - Output: `[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 10` 12 | - `-10 <= nums[i] <= 10` 13 | - All elements in `nums` are unique. 14 | 15 | ## Solution 16 | 17 | ### JavaScript 18 | ```javascript 19 | function subsets(nums) { 20 | const result = []; 21 | 22 | function backtrack(index, current) { 23 | result.push([...current]); 24 | for (let i = index; i < nums.length; i++) { 25 | current.push(nums[i]); 26 | backtrack(i + 1, current); 27 | current.pop(); 28 | } 29 | } 30 | 31 | backtrack(0, []); 32 | return result; 33 | } 34 | ``` 35 | 36 | ## Reasoning 37 | - **Approach**: Use backtracking to generate all subsets. At each index, include or exclude the current number, adding the current subset to the result at each step. Use an index to avoid duplicates. 38 | - **Why Backtracking?**: Efficiently explores all possible subsets by making choices at each step. 39 | - **Edge Cases**: 40 | - Empty array: Return `[[]]`. 41 | - Single element: Return `[[], [element]]`. 42 | - **Optimizations**: Add subset at each step; copy current list to avoid reference issues. 43 | 44 | ## Complexity Analysis 45 | - **Time Complexity**: O(2^n), where n is the length of `nums`, as there are 2^n possible subsets. 46 | - **Space Complexity**: O(n) for the recursion stack, plus O(2^n) for the output. 47 | 48 | ## Best Practices 49 | - Use clear variable names (e.g., `index`, `current`). 50 | - For Python, use type hints and list copying. 51 | - For JavaScript, use spread operator for copying. 52 | - For Java, use `ArrayList` and follow Google Java Style Guide. 53 | - Include empty subset in results. 54 | 55 | ## Alternative Approaches 56 | - **Bit Manipulation**: Use binary numbers to represent subsets (O(2^n) time). Less intuitive. 57 | - **Iterative**: Build subsets by adding each element to existing subsets (same complexity). More complex. -------------------------------------------------------------------------------- /JavaScript/Backtracking/Easy/combinations.md: -------------------------------------------------------------------------------- 1 | # Combinations 2 | 3 | ## Problem Statement 4 | Given two integers `n` and `k`, return all possible combinations of `k` numbers chosen from the range `[1, n]`. You may return the answer in any order. 5 | 6 | **Example**: 7 | - Input: `n = 4, k = 2` 8 | - Output: `[[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]` 9 | 10 | **Constraints**: 11 | - `1 <= n <= 20` 12 | - `1 <= k <= n` 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | function combine(n, k) { 19 | const result = []; 20 | 21 | function backtrack(start, current) { 22 | if (current.length === k) { 23 | result.push([...current]); 24 | return; 25 | } 26 | for (let i = start; i <= n; i++) { 27 | current.push(i); 28 | backtrack(i + 1, current); 29 | current.pop(); 30 | } 31 | } 32 | 33 | backtrack(1, []); 34 | return result; 35 | } 36 | ``` 37 | 38 | ## Reasoning 39 | - **Approach**: Use backtracking to build combinations. Start from 1 and add numbers up to `n`, ensuring each combination has `k` numbers. Use a start index to avoid duplicates and maintain order. 40 | - **Why Backtracking?**: Systematically generates all valid combinations while pruning invalid branches. 41 | - **Edge Cases**: 42 | - `k = 0`: Return empty list of lists. 43 | - `k = n`: Return single combination of all numbers. 44 | - **Optimizations**: Copy current list to result to avoid reference issues; use start index to ensure ascending order. 45 | 46 | ## Complexity Analysis 47 | - **Time Complexity**: O(n choose k) = O(n! / (k!(n-k)!)), the number of k-combinations. 48 | - **Space Complexity**: O(k) for the recursion stack, plus O(n choose k) for the output. 49 | 50 | ## Best Practices 51 | - Use clear variable names (e.g., `start`, `current`). 52 | - For Python, use type hints and list copying. 53 | - For JavaScript, use spread operator for copying. 54 | - For Java, use `ArrayList` and follow Google Java Style Guide. 55 | - Use start index to avoid duplicate combinations. 56 | 57 | ## Alternative Approaches 58 | - **Iterative**: Use a loop to generate combinations (same complexity). More complex to implement. 59 | - **Math-Based**: Use combinatorial formulas (complex to code). -------------------------------------------------------------------------------- /Numpy/Medium/array_broadcasting.md: -------------------------------------------------------------------------------- 1 | # Array Broadcasting 2 | 3 | ## Problem Statement 4 | Write a NumPy program to perform element-wise addition of a 1D array to each row of a 2D array using broadcasting. 5 | 6 | **Input**: 7 | - `A`: 2D array of shape `(m, n)` (e.g., `[[1, 2, 3], [4, 5, 6]]`) 8 | - `B`: 1D array of shape `(n,)` (e.g., `[10, 20, 30]`) 9 | 10 | **Output**: 11 | - 2D array of shape `(m, n)` (e.g., `[[11, 22, 33], [14, 25, 36]]`) 12 | 13 | **Constraints**: 14 | - `1 <= m, n <= 1000` 15 | - `B.shape[0] = A.shape[1]` 16 | - `-10^5 <= A[i][j], B[i] <= 10^5` 17 | 18 | ## Solution 19 | ```python 20 | import numpy as np 21 | 22 | def array_broadcasting(A: list, B: list) -> np.ndarray: 23 | # Convert to numpy arrays and broadcast 24 | A = np.array(A) 25 | B = np.array(B) 26 | return A + B 27 | ``` 28 | 29 | ## Reasoning 30 | - **Approach**: Convert input lists to NumPy arrays. Use NumPy’s broadcasting to add `B` to each row of `A`. Return the result. 31 | - **Why Broadcasting?**: Automatically aligns arrays of compatible shapes, avoiding explicit loops. 32 | - **Edge Cases**: 33 | - Shape mismatch: Ensured by `B.shape[0] = A.shape[1]`. 34 | - Single row: Broadcasting works as expected. 35 | - Large values: NumPy handles with float64 precision. 36 | - **Optimizations**: Broadcasting is a zero-copy operation, highly efficient. 37 | 38 | ## Performance Analysis 39 | - **Time Complexity**: O(m * n), where m, n are dimensions of A. 40 | - **Space Complexity**: O(m * n) for the output array. 41 | - **NumPy Efficiency**: Broadcasting uses C-based operations for speed. 42 | 43 | ## Best Practices 44 | - Use broadcasting for element-wise operations. 45 | - Ensure compatible shapes for broadcasting. 46 | - Follow PEP 8 for Python code style. 47 | 48 | ## Alternative Approaches 49 | - **Manual Loop**: Add manually (O(m * n), slower). 50 | ```python 51 | def array_broadcasting(A: list, B: list) -> list: 52 | result = [[A[i][j] + B[j] for j in range(len(B))] for i in range(len(A))] 53 | return result 54 | ``` 55 | - **np.add**: Explicit function call (O(m * n), same performance). 56 | ```python 57 | import numpy as np 58 | def array_broadcasting(A: list, B: list) -> np.ndarray: 59 | return np.add(np.array(A), np.array(B)) 60 | ``` -------------------------------------------------------------------------------- /Python/Arrays/Hard/maximum_subarray_product.md: -------------------------------------------------------------------------------- 1 | # Maximum Subarray Product 2 | 3 | ## Problem Statement 4 | Given an integer array `nums`, find a contiguous non-empty subarray with the largest product, and return that product. 5 | 6 | **Example**: 7 | - Input: `nums = [2,3,-2,4]` 8 | - Output: `6` 9 | - Explanation: Subarray `[2,3]` has the largest product `6`. 10 | 11 | **Constraints**: 12 | - `1 <= nums.length <= 2 * 10^4` 13 | - `-10 <= nums[i] <= 10` 14 | - The product of any subarray is guaranteed to fit in a 32-bit integer. 15 | 16 | ## Solution 17 | 18 | ### Python 19 | ```python 20 | def maxProduct(nums: list[int]) -> int: 21 | max_so_far = min_so_far = result = nums[0] 22 | for num in nums[1:]: 23 | temp_max = max(num, max_so_far * num, min_so_far * num) 24 | min_so_far = min(num, max_so_far * num, min_so_far * num) 25 | max_so_far = temp_max 26 | result = max(result, max_so_far) 27 | return result 28 | ``` 29 | 30 | ## Reasoning 31 | - **Approach**: Track maximum and minimum products ending at each index, as a negative number can turn a minimum product into a maximum with another negative number. Update `max_so_far`, `min_so_far`, and global `result` at each step. 32 | - **Why Track Min?**: Negative numbers can flip maximum to minimum products, so we need both. 33 | - **Edge Cases**: 34 | - Single element: Return that element. 35 | - Zeros: Reset product, consider single numbers. 36 | - All negatives: Maximum might be a single number or product of two negatives. 37 | - **Optimizations**: Single pass; constant space. 38 | 39 | ## Complexity Analysis 40 | - **Time Complexity**: O(n), where n is the length of `nums`. Single pass through the array. 41 | - **Space Complexity**: O(1), using only constant space. 42 | 43 | ## Best Practices 44 | - Use clear variable names (e.g., `max_so_far`, `min_so_far`). 45 | - For Python, use type hints for clarity. 46 | - For JavaScript, use `Math.max/min` for readability. 47 | - For Java, follow Google Java Style Guide. 48 | - Track both max and min products to handle negative numbers. 49 | 50 | ## Alternative Approaches 51 | - **Brute Force**: Check all subarrays (O(n²) time). Inefficient. 52 | - **Divide and Conquer**: Split array and compute max product (O(n log n) time). Too complex. -------------------------------------------------------------------------------- /Java/Dynamic_Programming/Easy/min_cost_climbing_stairs.md: -------------------------------------------------------------------------------- 1 | # Min Cost Climbing Stairs 2 | 3 | ## Problem Statement 4 | You are given an array `cost` where `cost[i]` is the cost of climbing the ith step. You can climb 1 or 2 steps at a time. You can start from step 0 or 1. Return the minimum cost to reach the top (beyond the last step). 5 | 6 | **Example**: 7 | - Input: `cost = [10,15,20]` 8 | - Output: `15` 9 | - Explanation: Start at step 1 (15), then reach the top (0 cost). 10 | 11 | **Constraints**: 12 | - `2 <= cost.length <= 1000` 13 | - `0 <= cost[i] <= 999` 14 | 15 | ## Solution 16 | 17 | ### Java 18 | ```java 19 | class Solution { 20 | public int minCostClimbingStairs(int[] cost) { 21 | int n = cost.length; 22 | int[] dp = new int[n + 1]; 23 | for (int i = 2; i <= n; i++) { 24 | dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]); 25 | } 26 | return dp[n]; 27 | } 28 | } 29 | ``` 30 | 31 | ## Reasoning 32 | - **Approach**: Use dynamic programming to compute the minimum cost to reach each step. For step `i`, take the minimum of coming from `i-1` or `i-2`: `dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])`. The top is beyond the last step, so return `dp[n]`. 33 | - **Why DP?**: Avoids recomputing costs by storing minimum costs for each step. 34 | - **Edge Cases**: 35 | - `n = 2`: Return minimum of `cost[0]` or `cost[1]`. 36 | - **Optimizations**: Use array-based DP; can optimize to O(1) space with two variables. 37 | 38 | ## Complexity Analysis 39 | - **Time Complexity**: O(n), single loop from 2 to n. 40 | - **Space Complexity**: O(n) for the DP array. Can be optimized to O(1) using two variables. 41 | 42 | ## Best Practices 43 | - Use clear variable names (e.g., `dp` for dynamic programming array). 44 | - For Python, use type hints for clarity. 45 | - For JavaScript, use array initialization with `fill`. 46 | - For Java, follow Google Java Style Guide. 47 | - Initialize `dp[0]` and `dp[1]` as 0 since starting costs are free. 48 | 49 | ## Alternative Approaches 50 | - **Optimized Space DP**: Use two variables (O(n) time, O(1) space). 51 | - **Recursion with Memoization**: Cache results (O(n) time, O(n) space). Less efficient than iterative. 52 | - **Brute Force**: Try all paths (O(2^n) time). Too slow. -------------------------------------------------------------------------------- /Numpy/Hard/fourier_transform.md: -------------------------------------------------------------------------------- 1 | # Fourier Transform 2 | 3 | ## Problem Statement 4 | Write a NumPy program to apply Fast Fourier Transform (FFT) to a 1D signal. 5 | 6 | **Input**: 7 | - `signal`: 1D array of numbers (e.g., `[1, 2, 3, 4]`) 8 | 9 | **Output**: 10 | - 1D array of complex FFT coefficients 11 | 12 | **Constraints**: 13 | - `1 <= len(signal) <= 10^5` 14 | - `-10^5 <= signal[i] <= 10^5` 15 | 16 | ## Solution 17 | ```python 18 | import numpy as np 19 | 20 | def fourier_transform(signal: list) -> np.ndarray: 21 | # Convert to numpy array and compute FFT 22 | return np.fft.fft(np.array(signal)) 23 | ``` 24 | 25 | ## Reasoning 26 | - **Approach**: Convert input list to NumPy array. Use `np.fft.fft` to compute the Fast Fourier Transform. Return the complex coefficients. 27 | - **Why np.fft.fft?**: Implements efficient FFT algorithm (Cooley-Tukey), optimal for signal processing. 28 | - **Edge Cases**: 29 | - Single element: Returns same element. 30 | - Small arrays: FFT works efficiently. 31 | - Large values: Handled with complex128 precision. 32 | - **Optimizations**: `np.fft.fft` uses optimized FFT implementation. 33 | 34 | ## Performance Analysis 35 | - **Time Complexity**: O(n log n), where n is the signal length, for FFT computation. 36 | - **Space Complexity**: O(n) for the output array. 37 | - **NumPy Efficiency**: Uses optimized FFTW library for fast computation. 38 | 39 | ## Best Practices 40 | - Use `np.fft.fft` for Fourier transforms. 41 | - Ensure input is a 1D array. 42 | - Follow PEP 8 for Python code style. 43 | 44 | ## Alternative Approaches 45 | - **Manual DFT**: Compute Discrete Fourier Transform (O(n^2), slow). 46 | ```python 47 | import numpy as np 48 | def fourier_transform(signal: list) -> np.ndarray: 49 | signal = np.array(signal) 50 | n = len(signal) 51 | result = np.zeros(n, dtype=np.complex128) 52 | for k in range(n): 53 | for t in range(n): 54 | result[k] += signal[t] * np.exp(-2j * np.pi * t * k / n) 55 | return result 56 | ``` 57 | - **SciPy FFT**: Use SciPy’s FFT (O(n log n), similar performance). 58 | ```python 59 | from scipy.fft import fft 60 | import numpy as np 61 | def fourier_transform(signal: list) -> np.ndarray: 62 | return fft(np.array(signal)) 63 | ``` -------------------------------------------------------------------------------- /Python/Dynamic_Programming/Easy/min_cost_climbing_stairs.md: -------------------------------------------------------------------------------- 1 | # Min Cost Climbing Stairs 2 | 3 | ## Problem Statement 4 | You are given an array `cost` where `cost[i]` is the cost of climbing the ith step. You can climb 1 or 2 steps at a time. You can start from step 0 or 1. Return the minimum cost to reach the top (beyond the last step). 5 | 6 | **Example**: 7 | - Input: `cost = [10,15,20]` 8 | - Output: `15` 9 | - Explanation: Start at step 1 (15), then reach the top (0 cost). 10 | 11 | **Constraints**: 12 | - `2 <= cost.length <= 1000` 13 | - `0 <= cost[i] <= 999` 14 | 15 | ## Solution 16 | 17 | ### Java 18 | ```java 19 | class Solution { 20 | public int minCostClimbingStairs(int[] cost) { 21 | int n = cost.length; 22 | int[] dp = new int[n + 1]; 23 | for (int i = 2; i <= n; i++) { 24 | dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]); 25 | } 26 | return dp[n]; 27 | } 28 | } 29 | ``` 30 | 31 | ## Reasoning 32 | - **Approach**: Use dynamic programming to compute the minimum cost to reach each step. For step `i`, take the minimum of coming from `i-1` or `i-2`: `dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])`. The top is beyond the last step, so return `dp[n]`. 33 | - **Why DP?**: Avoids recomputing costs by storing minimum costs for each step. 34 | - **Edge Cases**: 35 | - `n = 2`: Return minimum of `cost[0]` or `cost[1]`. 36 | - **Optimizations**: Use array-based DP; can optimize to O(1) space with two variables. 37 | 38 | ## Complexity Analysis 39 | - **Time Complexity**: O(n), single loop from 2 to n. 40 | - **Space Complexity**: O(n) for the DP array. Can be optimized to O(1) using two variables. 41 | 42 | ## Best Practices 43 | - Use clear variable names (e.g., `dp` for dynamic programming array). 44 | - For Python, use type hints for clarity. 45 | - For JavaScript, use array initialization with `fill`. 46 | - For Java, follow Google Java Style Guide. 47 | - Initialize `dp[0]` and `dp[1]` as 0 since starting costs are free. 48 | 49 | ## Alternative Approaches 50 | - **Optimized Space DP**: Use two variables (O(n) time, O(1) space). 51 | - **Recursion with Memoization**: Cache results (O(n) time, O(n) space). Less efficient than iterative. 52 | - **Brute Force**: Try all paths (O(2^n) time). Too slow. -------------------------------------------------------------------------------- /Python/Sorting_Searching/Medium/sort_colors.md: -------------------------------------------------------------------------------- 1 | # Sort Colors 2 | 3 | ## Problem Statement 4 | Given an array `nums` with n objects colored 0, 1, or 2, sort them in-place so that objects of the same color are adjacent, with the colors in the order 0, 1, and 2. 5 | 6 | **Example**: 7 | - Input: `nums = [2,0,2,1,1,0]` 8 | - Output: `[0,0,1,1,2,2]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 300` 12 | - `nums[i]` is 0, 1, or 2. 13 | 14 | ## Solution 15 | 16 | ### Python 17 | ```python 18 | def sortColors(nums: list[int]) -> None: 19 | low, mid, high = 0, 0, len(nums) - 1 20 | 21 | while mid <= high: 22 | if nums[mid] == 0: 23 | nums[low], nums[mid] = nums[mid], nums[low] 24 | low += 1 25 | mid += 1 26 | elif nums[mid] == 1: 27 | mid += 1 28 | else: 29 | nums[mid], nums[high] = nums[high], nums[mid] 30 | high -= 1 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use the Dutch National Flag algorithm with three pointers: `low` for 0s, `mid` for 1s, and `high` for 2s. Swap elements to place 0s before `low`, 1s between `low` and `high`, and 2s after `high`. Move pointers based on `nums[mid]`. 35 | - **Why Dutch National Flag?**: Sorts three distinct values in one pass with O(1) space. 36 | - **Edge Cases**: 37 | - Single element: Already sorted. 38 | - All same value: Algorithm handles efficiently. 39 | - Small array: Works correctly. 40 | - **Optimizations**: In-place sorting; single pass with three pointers. 41 | 42 | ## Complexity Analysis 43 | - **Time Complexity**: O(n), where n is the length of `nums`, as we traverse the array once. 44 | - **Space Complexity**: O(1), as we sort in-place using only pointers. 45 | 46 | ## Best Practices 47 | - Use clear variable names (e.g., `low`, `mid`, `high`). 48 | - For Python, use type hints and tuple unpacking for swaps. 49 | - For JavaScript, use array destructuring for swaps. 50 | - For Java, follow Google Java Style Guide and use explicit swaps. 51 | - Optimize with single-pass algorithm. 52 | 53 | ## Alternative Approaches 54 | - **Counting Sort**: Count 0s, 1s, 2s, then rewrite array (O(n) time, O(1) space). Two passes, less elegant. 55 | - **Standard Sort**: Use built-in sort (O(n log n) time). Overkill for three values. -------------------------------------------------------------------------------- /Python/Sorting_Searching/Medium/top_k_frequent_elements.md: -------------------------------------------------------------------------------- 1 | # Top K Frequent Elements 2 | 3 | ## Problem Statement 4 | Given an integer array `nums` and an integer `k`, return the `k` most frequent elements. You may return the answer in any order. 5 | 6 | **Example**: 7 | - Input: `nums = [1,1,1,2,2,3], k = 2` 8 | - Output: `[1,2]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 10^5` 12 | - `-10^4 <= nums[i] <= 10^4` 13 | - `k` is in the range `[1, the number of unique elements in the array]`. 14 | 15 | ## Solution 16 | 17 | ### Python 18 | ```python 19 | from collections import Counter 20 | import heapq 21 | 22 | def topKFrequent(nums: list[int], k: int) -> list[int]: 23 | count = Counter(nums) 24 | heap = [] 25 | for num, freq in count.items(): 26 | heapq.heappush(heap, (freq, num)) 27 | if len(heap) > k: 28 | heapq.heappop(heap) 29 | 30 | return [num for _, num in heap] 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Count frequencies using a hash map. Use a min-heap of size k to store elements by frequency. For each unique element, add to the heap and remove the smallest frequency if size exceeds k. Return the remaining elements. 35 | - **Why Min-Heap?**: Efficiently maintains k most frequent elements with O(log k) operations. 36 | - **Edge Cases**: 37 | - k=1: Return most frequent element. 38 | - Single unique element: Return it if k=1. 39 | - k equals unique elements: Return all. 40 | - **Optimizations**: Use min-heap to limit size to k; avoid sorting frequencies. 41 | 42 | ## Complexity Analysis 43 | - **Time Complexity**: O(n log k), where n is the length of `nums`. Counting is O(n), heap operations are O(log k) per unique element. 44 | - **Space Complexity**: O(n) for the hash map, O(k) for the heap. 45 | 46 | ## Best Practices 47 | - Use clear variable names (e.g., `count`, `heap`). 48 | - For Python, use `Counter` and `heapq`. 49 | - For JavaScript, use `Map` and priority queue library. 50 | - For Java, use `HashMap` and `PriorityQueue`, follow Google Java Style Guide. 51 | - Process frequencies efficiently with heap. 52 | 53 | ## Alternative Approaches 54 | - **Sorting**: Sort by frequency (O(n log n) time). Less efficient. 55 | - **Bucket Sort**: Use frequency buckets (O(n) time, O(n) space). Faster but more complex. -------------------------------------------------------------------------------- /Java/Linked_Lists/Easy/reverse_linked_list.md: -------------------------------------------------------------------------------- 1 | # Reverse Linked List 2 | 3 | ## Problem Statement 4 | Given the head of a singly linked list, reverse the list and return its head. 5 | 6 | **Example**: 7 | - Input: `head = [1,2,3,4,5]` 8 | - Output: `[5,4,3,2,1]` 9 | 10 | **Constraints**: 11 | - The number of nodes in the list is in the range `[0, 5000]`. 12 | - `-5000 <= Node.val <= 5000` 13 | 14 | ## Solution 15 | 16 | ### Java 17 | ```java 18 | class ListNode { 19 | int val; 20 | ListNode next; 21 | ListNode(int val) { this.val = val; } 22 | ListNode(int val, ListNode next) { this.val = val; this.next = next; } 23 | } 24 | 25 | class Solution { 26 | public ListNode reverseList(ListNode head) { 27 | ListNode prev = null; 28 | ListNode current = head; 29 | 30 | while (current != null) { 31 | ListNode nextNode = current.next; 32 | current.next = prev; 33 | prev = current; 34 | current = nextNode; 35 | } 36 | 37 | return prev; 38 | } 39 | } 40 | ``` 41 | 42 | ## Reasoning 43 | - **Approach**: Iteratively reverse the list by adjusting pointers. For each node, save the next node, point the current node’s next to the previous node, and move forward. The `prev` node becomes the new head. 44 | - **Why Iterative?**: Avoids recursion stack space, making it more efficient for large lists. 45 | - **Edge Cases**: 46 | - Empty list: Return null. 47 | - Single node: Return the node. 48 | - **Optimizations**: In-place reversal to minimize space; single pass through the list. 49 | 50 | ## Complexity Analysis 51 | - **Time Complexity**: O(n), where n is the number of nodes, as we traverse the list once. 52 | - **Space Complexity**: O(1), as we only use a few pointers. 53 | 54 | ## Best Practices 55 | - Use clear variable names (e.g., `prev`, `current`). 56 | - For Python, use type hints for clarity. 57 | - For JavaScript, use descriptive variable names. 58 | - For Java, follow Google Java Style Guide. 59 | - Handle null checks explicitly. 60 | 61 | ## Alternative Approaches 62 | - **Recursive**: Recursively reverse by adjusting pointers (O(n) time, O(n) space due to recursion stack). 63 | - **Stack-Based**: Push nodes onto a stack and pop to reverse (O(n) time, O(n) space). Less efficient. -------------------------------------------------------------------------------- /Python/Arrays/Medium/container_with_most_water.md: -------------------------------------------------------------------------------- 1 | # Container With Most Water 2 | 3 | ## Problem Statement 4 | Given an integer array `height` of length `n`, find two lines that, together with the x-axis, form a container with the most water. Return the maximum area. 5 | 6 | **Example**: 7 | - Input: `height = [1,8,6,2,5,4,8,3,7]` 8 | - Output: `49` 9 | - Explanation: The container formed by indices 1 and 8 (heights 8 and 7) has area `7 * (8-1) = 49`. 10 | 11 | **Constraints**: 12 | - `n == height.length` 13 | - `2 <= n <= 10^5` 14 | - `0 <= height[i] <= 10^4` 15 | 16 | ## Solution 17 | 18 | ### Python 19 | ```python 20 | def maxArea(height: list[int]) -> int: 21 | left, right = 0, len(height) - 1 22 | max_area = 0 23 | while left < right: 24 | width = right - left 25 | max_area = max(max_area, min(height[left], height[right]) * width) 26 | if height[left] < height[right]: 27 | left += 1 28 | else: 29 | right -= 1 30 | return max_area 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use two pointers (left, right) starting at array ends. Compute area as `min(height[left], height[right]) * (right - left)`. Move the pointer with the smaller height inward to maximize potential area. 35 | - **Why Two Pointers?**: Moving the smaller height maximizes area potential, as width decreases but height might increase. 36 | - **Edge Cases**: 37 | - Two elements: Compute single area. 38 | - All equal heights: Handled by moving either pointer. 39 | - **Optimizations**: Single pass with two pointers; no extra space needed. 40 | 41 | ## Complexity Analysis 42 | - **Time Complexity**: O(n), where n is the length of `height`. Single pass with two pointers. 43 | - **Space Complexity**: O(1), using only constant space. 44 | 45 | ## Best Practices 46 | - Use clear variable names (e.g., `left`, `right`, `max_area`). 47 | - For Python, use type hints for clarity. 48 | - For JavaScript, use `Math.min/max` for readability. 49 | - For Java, follow Google Java Style Guide. 50 | - Move smaller height to optimize area calculation. 51 | 52 | ## Alternative Approaches 53 | - **Brute Force**: Check all pairs of lines (O(n²) time). Inefficient for large inputs. 54 | - **Greedy with Sorting**: Sort heights and try combinations (O(n log n) time). Less efficient. -------------------------------------------------------------------------------- /JavaScript/Arrays/Easy/single_number.md: -------------------------------------------------------------------------------- 1 | # Single Number 2 | 3 | ## Problem Statement 4 | Given a non-empty array of integers `nums`, every element appears twice except for one. Find that single one. You must implement a solution with a linear runtime complexity and use only constant extra space. 5 | 6 | **Example**: 7 | - Input: `nums = [2,2,1]` 8 | - Output: `1` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 3 * 10^4` 12 | - `-3 * 10^4 <= nums[i] <= 3 * 10^4` 13 | - Each element appears twice except for one element which appears once. 14 | 15 | ## Solution 16 | 17 | ### JavaScript 18 | ```javascript 19 | function singleNumber(nums) { 20 | let result = 0; 21 | for (const num of nums) { 22 | result ^= num; 23 | } 24 | return result; 25 | } 26 | ``` 27 | 28 | ## Reasoning 29 | - **Approach**: Use XOR bitwise operation. XOR of a number with itself is 0, and XOR of a number with 0 is the number itself. Since all numbers except one appear twice, XORing all elements cancels out pairs, leaving the single number. 30 | - **Why XOR?**: It meets the requirement for O(n) time and O(1) space, as it processes each element once without extra storage. 31 | - **Edge Cases**: 32 | - Single element: Returns that element. 33 | - All pairs except one: XOR correctly isolates the single number. 34 | - **Optimizations**: Single pass with a single variable; no additional data structures needed. 35 | 36 | ## Complexity Analysis 37 | - **Time Complexity**: O(n), where n is the length of `nums`. Single pass through the array. 38 | - **Space Complexity**: O(1), as only one variable is used. 39 | 40 | ## Best Practices 41 | - Use clear variable names (e.g., `result` for XOR accumulator). 42 | - For Python, include type hints for clarity. 43 | - For JavaScript, use `for...of` for readable iteration. 44 | - For Java, follow Google Java Style Guide. 45 | - Leverage XOR’s properties for elegant, efficient solutions. 46 | 47 | ## Alternative Approaches 48 | - **Hash Set**: Store elements in a set, removing duplicates (O(n) time, O(n) space). Violates constant space requirement. 49 | - **Hash Map**: Count frequencies and find the element with count 1 (O(n) time, O(n) space). Also violates space constraint. 50 | - **Sorting**: Sort and find the unpaired element (O(n log n) time, O(1) space). Slower than XOR. -------------------------------------------------------------------------------- /JavaScript/Dynamic_Programming/Medium/unique_paths.md: -------------------------------------------------------------------------------- 1 | # Unique Paths 2 | 3 | ## Problem Statement 4 | A robot starts at the top-left corner of an `m x n` grid and can only move right or down. Return the number of unique paths to reach the bottom-right corner. 5 | 6 | **Example**: 7 | - Input: `m = 3, n = 2` 8 | - Output: `3` 9 | - Explanation: Three paths: (right, down), (down, right), (down, down, right). 10 | 11 | **Constraints**: 12 | - `1 <= m, n <= 100` 13 | - Answer will fit in a 32-bit signed integer. 14 | 15 | ## Solution 16 | 17 | ### JavaScript 18 | ```javascript 19 | function uniquePaths(m, n) { 20 | const dp = Array(m).fill().map(() => Array(n).fill(1)); 21 | for (let i = 1; i < m; i++) { 22 | for (let j = 1; j < n; j++) { 23 | dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; 24 | } 25 | } 26 | return dp[m - 1][n - 1]; 27 | } 28 | ``` 29 | 30 | ## Reasoning 31 | - **Approach**: Use a 2D DP array where `dp[i][j]` represents the number of unique paths to reach `(i,j)`. Each cell can be reached from above (`dp[i-1][j]`) or left (`dp[i][j-1]`), so `dp[i][j] = dp[i-1][j] + dp[i][j-1]`. Initialize first row and column to 1 (only one way to reach those cells). 32 | - **Why DP?**: Avoids recomputing paths by storing results for each cell. 33 | - **Edge Cases**: 34 | - `m = 1` or `n = 1`: Only one path (all right or all down). 35 | - **Optimizations**: Use 2D array; can optimize to O(min(m,n)) space using a 1D array. 36 | 37 | ## Complexity Analysis 38 | - **Time Complexity**: O(m * n), filling the DP array. 39 | - **Space Complexity**: O(m * n) for the 2D DP array. Can be optimized to O(min(m,n)) with a 1D array. 40 | 41 | ## Best Practices 42 | - Use clear variable names (e.g., `dp` for dynamic programming array). 43 | - For Python, use type hints and list comprehension. 44 | - For JavaScript, use array methods for initialization. 45 | - For Java, follow Google Java Style Guide. 46 | - Initialize boundaries to 1 for clarity. 47 | 48 | ## Alternative Approaches 49 | - **Optimized Space DP**: Use a 1D array (O(m * n) time, O(min(m,n)) space). 50 | - **Combinatorial**: Compute `(m+n-2) choose (m-1)` (O(min(m,n)) time). Requires careful handling of large numbers. 51 | - **Recursion with Memoization**: Cache results (O(m * n) time, O(m * n) space). Less efficient than iterative. -------------------------------------------------------------------------------- /JavaScript/Arrays/Hard/first_missing_positive.md: -------------------------------------------------------------------------------- 1 | # First Missing Positive 2 | 3 | ## Problem Statement 4 | Given an unsorted integer array `nums`, return the smallest missing positive integer. You must implement an algorithm that runs in O(n) time and uses O(1) space. 5 | 6 | **Example**: 7 | - Input: `nums = [1,2,0]` 8 | - Output: `3` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 5 * 10^5` 12 | - `-2^31 <= nums[i] <= 2^31 - 1` 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | function firstMissingPositive(nums) { 19 | const n = nums.length; 20 | for (let i = 0; i < n; i++) { 21 | if (nums[i] <= 0 || nums[i] > n) { 22 | nums[i] = n + 1; 23 | } 24 | } 25 | for (let i = 0; i < n; i++) { 26 | const num = Math.abs(nums[i]); 27 | if (num <= n) { 28 | nums[num - 1] = -Math.abs(nums[num - 1]); 29 | } 30 | } 31 | for (let i = 0; i < n; i++) { 32 | if (nums[i] > 0) { 33 | return i + 1; 34 | } 35 | } 36 | return n + 1; 37 | } 38 | ``` 39 | 40 | ## Reasoning 41 | - **Approach**: Use the array itself as a hash table. Ignore non-positive and numbers > n. Place each number `x` at index `x-1` by marking the index negative. The first positive index indicates the missing number. 42 | - **Why In-Place Marking?**: Achieves O(1) space by using the array to track presence of numbers 1 to n. 43 | - **Edge Cases**: 44 | - Empty array: Return 1. 45 | - All numbers present: Return n + 1. 46 | - Negative numbers: Ignored via preprocessing. 47 | - **Optimizations**: Three linear passes; no extra space. 48 | 49 | ## Complexity Analysis 50 | - **Time Complexity**: O(n), where n is the length of `nums`. Three passes through the array. 51 | - **Space Complexity**: O(1), using the array itself. 52 | 53 | ## Best Practices 54 | - Use clear variable names (e.g., `num`, `n`). 55 | - For Python, use type hints and handle edge cases. 56 | - For JavaScript, use `Math.abs` for clarity. 57 | - For Java, follow Google Java Style Guide. 58 | - Use array indices to avoid extra space. 59 | 60 | ## Alternative Approaches 61 | - **Hash Set**: Store numbers and check for missing (O(n) time, O(n) space). Violates space constraint. 62 | - **Sorting**: Sort and find missing number (O(n log n) time). Too slow. -------------------------------------------------------------------------------- /MySQL/Hard/shortest_distance_in_a_line.md: -------------------------------------------------------------------------------- 1 | # Shortest Distance in a Line 2 | 3 | ## Problem Statement 4 | Write a SQL query to find the shortest distance between any two points in the `Point` table. 5 | 6 | **Table: Point** 7 | ``` 8 | +-------------+------+ 9 | | Column Name | Type | 10 | +-------------+------+ 11 | | x | int | 12 | +-------------+------+ 13 | x is the primary key. 14 | ``` 15 | 16 | **Example**: 17 | - Input: `[[-1], [0], [2]]` 18 | - Output: `1` 19 | - Explanation: The shortest distance is between -1 and 0 (or 0 and 2), which is 1. 20 | 21 | **Constraints**: 22 | - `2 <= Point.x <= 10^4` 23 | - `Point.x` contains unique values. 24 | 25 | ## Solution 26 | ```sql 27 | SELECT MIN(ABS(p1.x - p2.x)) AS shortest 28 | FROM Point p1 29 | JOIN Point p2 ON p1.x != p2.x; 30 | ``` 31 | 32 | ## Reasoning 33 | - **Approach**: Use a self-join to pair all distinct points (`p1.x != p2.x`). Calculate the absolute difference between their `x` values using `ABS(p1.x - p2.x)`. Use `MIN` to find the smallest distance. 34 | - **Why Self-Join?**: Allows comparison of all pairs of points to compute distances. 35 | - **Edge Cases**: 36 | - Two points: Returns their distance. 37 | - Multiple points: Finds minimum distance. 38 | - No duplicate x values: Ensured by constraints. 39 | - **Optimizations**: Use `MIN` to avoid sorting entire result; `!=` ensures no self-pairing. 40 | 41 | ## Performance Analysis 42 | - **Time Complexity**: O(n^2) for self-join, where n is the number of rows in `Point`. `MIN` is computed during join. 43 | - **Space Complexity**: O(1), excluding output storage. 44 | - **Index Usage**: Primary key index on `x` optimizes join and comparison. 45 | 46 | ## Best Practices 47 | - Use clear aliases (e.g., `p1`, `p2`) for self-joins. 48 | - Use `ABS` for distance calculation. 49 | - Avoid unnecessary columns in output. 50 | - Format SQL consistently. 51 | 52 | ## Alternative Approaches 53 | - **Window Function**: Use `LEAD` to compare adjacent points (O(n log n), assumes sorted). 54 | ```sql 55 | SELECT MIN(ABS(x - LEAD(x) OVER (ORDER BY x))) AS shortest 56 | FROM Point; 57 | ``` 58 | - **Subquery**: Compute differences with subquery (O(n^2), less readable). 59 | ```sql 60 | SELECT MIN(ABS(p1.x - p2.x)) AS shortest 61 | FROM Point p1, Point p2 62 | WHERE p1.x < p2.x; 63 | ``` -------------------------------------------------------------------------------- /Numpy/Hard/eigenvalue_computation.md: -------------------------------------------------------------------------------- 1 | # Eigenvalue Computation 2 | 3 | ## Problem Statement 4 | Write a NumPy program to compute the eigenvalues of a square matrix. 5 | 6 | **Input**: 7 | - `A`: 2D array of shape `(n, n)` (e.g., `[[1, 2], [3, 4]]`) 8 | 9 | **Output**: 10 | - 1D array of eigenvalues (e.g., `[-0.37228132, 5.37228132]`) 11 | 12 | **Constraints**: 13 | - `1 <= n <= 1000` 14 | - `-10^5 <= A[i][j] <= 10^5` 15 | - `A` is a square matrix 16 | 17 | ## Solution 18 | ```python 19 | import numpy as np 20 | 21 | def eigenvalue_computation(A: list) -> np.ndarray: 22 | # Convert to numpy array and compute eigenvalues 23 | return np.linalg.eigvals(np.array(A)) 24 | ``` 25 | 26 | ## Reasoning 27 | - **Approach**: Convert input list to NumPy array. Use `np.linalg.eigvals` to compute eigenvalues. Return the result. 28 | - **Why np.linalg.eigvals?**: Optimized for eigenvalue computation using LAPACK, suitable for square matrices. 29 | - **Edge Cases**: 30 | - 1x1 matrix: Returns single eigenvalue. 31 | - Non-square matrix: Ensured by constraints. 32 | - Singular matrix: Returns valid eigenvalues (may include zeros). 33 | - **Optimizations**: `np.linalg.eigvals` uses efficient linear algebra routines. 34 | 35 | ## Performance Analysis 36 | - **Time Complexity**: O(n^3), where n is the matrix dimension, for eigenvalue computation. 37 | - **Space Complexity**: O(n) for the output array. 38 | - **NumPy Efficiency**: Uses LAPACK for optimized linear algebra. 39 | 40 | ## Best Practices 41 | - Use `np.linalg.eigvals` for eigenvalue computation. 42 | - Ensure input is a square matrix. 43 | - Follow PEP 8 for Python code style. 44 | 45 | ## Alternative Approaches 46 | - **Manual Eigenvalues**: Solve characteristic polynomial (O(n^3), less robust). 47 | ```python 48 | import numpy as np 49 | def eigenvalue_computation(A: list) -> np.ndarray: 50 | A = np.array(A) 51 | n = A.shape[0] 52 | # Compute characteristic polynomial coefficients 53 | coeffs = np.poly(A) 54 | # Find roots (eigenvalues) 55 | return np.roots(coeffs) 56 | ``` 57 | - **Full Eigen Decomposition**: Use `np.linalg.eig` (O(n^3), includes eigenvectors). 58 | ```python 59 | import numpy as np 60 | def eigenvalue_computation(A: list) -> np.ndarray: 61 | return np.linalg.eig(np.array(A))[0] 62 | ``` -------------------------------------------------------------------------------- /Java/Arrays/Easy/move_zeroes.md: -------------------------------------------------------------------------------- 1 | # Move Zeroes 2 | 3 | ## Problem Statement 4 | Given an integer array `nums`, move all `0`’s to the end of the array while maintaining the relative order of non-zero elements. The operation must be done in-place. 5 | 6 | **Example**: 7 | - Input: `nums = [0,1,0,3,12]` 8 | - Output: `[1,3,12,0,0]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 10^4` 12 | - `-2^31 <= nums[i] <= 2^31 - 1` 13 | 14 | ## Solution 15 | 16 | ### Java 17 | ```java 18 | class Solution { 19 | public void moveZeroes(int[] nums) { 20 | int nonZeroPos = 0; 21 | for (int i = 0; i < nums.length; i++) { 22 | if (nums[i] != 0) { 23 | int temp = nums[nonZeroPos]; 24 | nums[nonZeroPos] = nums[i]; 25 | nums[i] = temp; 26 | nonZeroPos++; 27 | } 28 | } 29 | } 30 | } 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use two pointers. Move all non-zero elements to the front by swapping with the `non_zero_pos` index, incrementing it each time. Zeros naturally shift to the end as non-zero elements are placed earlier. 35 | - **Why Two Pointers?**: This ensures in-place operation and maintains relative order without extra space. 36 | - **Edge Cases**: 37 | - All zeros or no zeros: Works correctly without special handling. 38 | - Single element: No change needed. 39 | - **Optimizations**: Single pass to move non-zeros; no need to explicitly set zeros at the end since swaps handle it. 40 | 41 | ## Complexity Analysis 42 | - **Time Complexity**: O(n), where n is the length of `nums`. Single pass through the array. 43 | - **Space Complexity**: O(1), as operations are in-place. 44 | 45 | ## Best Practices 46 | - Use descriptive variable names (e.g., `non_zero_pos`). 47 | - For Python, use type hints and ensure in-place modification. 48 | - For JavaScript, use array destructuring for clean swaps. 49 | - For Java, use explicit temporary variables for swaps and follow Google Java Style Guide. 50 | - Avoid unnecessary passes or extra arrays. 51 | 52 | ## Alternative Approaches 53 | - **Two Passes**: Move non-zeros to the front, then fill the rest with zeros (O(n) time, O(1) space). Less efficient due to extra pass. 54 | - **Extra Array**: Copy non-zeros to a new array, then zeros (O(n) time, O(n) space). Not in-place. -------------------------------------------------------------------------------- /Java/Arrays/Medium/rotate_array.md: -------------------------------------------------------------------------------- 1 | # Rotate Array 2 | 3 | ## Problem Statement 4 | Given an integer array `nums`, rotate the array to the right by `k` steps, where `k` is non-negative. The operation must be done in-place. 5 | 6 | **Example**: 7 | - Input: `nums = [1,2,3,4,5,6,7], k = 3` 8 | - Output: `[5,6,7,1,2,3,4]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 10^5` 12 | - `-2^31 <= nums[i] <= 2^31 - 1` 13 | - `0 <= k <= 10^5` 14 | 15 | ## Solution 16 | 17 | ### Java 18 | ```java 19 | class Solution { 20 | public void rotate(int[] nums, int k) { 21 | int n = nums.length; 22 | k = k % n; 23 | reverse(nums, 0, n - 1); 24 | reverse(nums, 0, k - 1); 25 | reverse(nums, k, n - 1); 26 | } 27 | 28 | private void reverse(int[] nums, int start, int end) { 29 | while (start < end) { 30 | int temp = nums[start]; 31 | nums[start] = nums[end]; 32 | nums[end] = temp; 33 | start++; 34 | end--; 35 | } 36 | } 37 | } 38 | ``` 39 | 40 | ## Reasoning 41 | - **Approach**: Use the reverse array method: reverse the entire array, then reverse the first `k` elements, then reverse the rest. This effectively rotates the array right by `k` steps in-place. 42 | - **Why Reverse?**: It’s an elegant way to achieve rotation in-place with O(n) time and O(1) space. 43 | - **Edge Cases**: 44 | - `k > n`: Use `k % n` to handle large `k`. 45 | - `k = 0` or `n = 1`: No rotation needed. 46 | - **Optimizations**: Modulo `k` to handle large rotations; in-place swaps to minimize space. 47 | 48 | ## Complexity Analysis 49 | - **Time Complexity**: O(n), where n is the length of `nums`. Three reverse passes. 50 | - **Space Complexity**: O(1), as operations are in-place. 51 | 52 | ## Best Practices 53 | - Use clear function names (e.g., `reverse`). 54 | - For Python, use type hints and modular helper functions. 55 | - For JavaScript, use array destructuring for swaps. 56 | - For Java, use private helper methods and follow Google Java Style Guide. 57 | - Handle large `k` with modulo. 58 | 59 | ## Alternative Approaches 60 | - **Cyclic Replacements**: Move each element to its new position (O(n) time, O(1) space). Complex to implement. 61 | - **Extra Array**: Copy elements to new positions (O(n) time, O(n) space). Not in-place. -------------------------------------------------------------------------------- /JavaScript/Trees/Easy/symmetric_tree.md: -------------------------------------------------------------------------------- 1 | # Symmetric Tree 2 | 3 | ## Problem Statement 4 | Given the root of a binary tree, check whether it is a mirror of itself (i.e., symmetric around its center). 5 | 6 | **Example**: 7 | - Input: `root = [1,2,2,3,4,4,3]` 8 | - Output: `true` 9 | 10 | **Constraints**: 11 | - The number of nodes is in the range `[1, 1000]`. 12 | - `-100 <= Node.val <= 100` 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | class Solution { 19 | isSymmetric(root) { 20 | function isMirror(left, right) { 21 | if (!left && !right) return true; 22 | if (!left || !right) return false; 23 | return (left.val === right.val && 24 | isMirror(left.left, right.right) && 25 | isMirror(left.right, right.left)); 26 | } 27 | 28 | return isMirror(root, root); 29 | } 30 | } 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use recursive mirror checking. Compare the left and right subtrees of the root, ensuring left’s left matches right’s right and left’s right matches right’s left. Check node values and recurse symmetrically. 35 | - **Why Recursive?**: Symmetry checking naturally compares mirrored subtrees, making recursion intuitive and concise. 36 | - **Edge Cases**: 37 | - Single node: Symmetric (true). 38 | - Empty tree: Handled by constraints (non-empty). 39 | - Unbalanced subtrees: Return false. 40 | - **Optimizations**: Recursive solution is clean; iterative possible but more complex. 41 | 42 | ## Complexity Analysis 43 | - **Time Complexity**: O(n), where n is the number of nodes, as each node is visited once. 44 | - **Space Complexity**: O(h), where h is the height of the tree, due to the recursion stack (O(n) in worst case for skewed tree). 45 | 46 | ## Best Practices 47 | - Use clear variable names (e.g., `left`, `right`). 48 | - For Python, use type hints and helper function. 49 | - For JavaScript, use strict equality (`===`). 50 | - For Java, follow Google Java Style Guide. 51 | - Ensure symmetric recursion for clarity. 52 | 53 | ## Alternative Approaches 54 | - **Iterative**: Use a queue to compare nodes level-by-level (O(n) time, O(w) space, where w is max width). More complex. 55 | - **BFS with Mirroring**: Compare level arrays (O(n) time, O(n) space). Less efficient. -------------------------------------------------------------------------------- /Python/Arrays/Easy/majority_element.md: -------------------------------------------------------------------------------- 1 | # Majority Element 2 | 3 | ## Problem Statement 4 | Given an array `nums` of size `n`, return the majority element. The majority element is the element that appears more than `⌊n/2⌋` times. You may assume the majority element always exists. 5 | 6 | **Example**: 7 | - Input: `nums = [2,2,1,1,1,2,2]` 8 | - Output: `2` 9 | - Explanation: `2` appears 4 times, which is more than `n/2 = 3.5`. 10 | 11 | **Constraints**: 12 | - `1 <= nums.length <= 5 * 10^4` 13 | - `-10^9 <= nums[i] <= 10^9` 14 | 15 | ## Solution 16 | 17 | ### Python 18 | ```python 19 | def majorityElement(nums: list[int]) -> int: 20 | count = 0 21 | candidate = 0 22 | for num in nums: 23 | if count == 0: 24 | candidate = num 25 | count += (1 if num == candidate else -1) 26 | return candidate 27 | ``` 28 | 29 | ## Reasoning 30 | - **Approach**: Use Boyer-Moore Voting Algorithm. Since the majority element appears more than `n/2` times, maintain a candidate and count. Increment count when seeing the candidate, decrement otherwise. When count reaches 0, pick a new candidate. The final candidate is the majority element. 31 | - **Why Boyer-Moore?**: It guarantees the majority element in a single pass without extra space, leveraging the fact that the majority element outweighs others. 32 | - **Edge Cases**: 33 | - Single element: Returns that element. 34 | - Majority element exists: Guaranteed by problem constraints. 35 | - **Optimizations**: Single pass with minimal variables; no need for validation due to problem assumptions. 36 | 37 | ## Complexity Analysis 38 | - **Time Complexity**: O(n), where n is the length of `nums`. Single pass through the array. 39 | - **Space Complexity**: O(1), as only two variables are used. 40 | 41 | ## Best Practices 42 | - Use clear variable names (e.g., `candidate`, `count`). 43 | - For Python, include type hints for clarity. 44 | - For JavaScript, use `for...of` for readability. 45 | - For Java, follow Google Java Style Guide. 46 | - Keep logic simple to leverage the algorithm’s elegance. 47 | 48 | ## Alternative Approaches 49 | - **Hash Map**: Count frequencies and return the element with count > `n/2` (O(n) time, O(n) space). 50 | - **Sorting**: Sort the array and return the middle element (O(n log n) time, O(1) space). Less efficient than Boyer-Moore. -------------------------------------------------------------------------------- /Pandas/Easy/invalid_tweets.md: -------------------------------------------------------------------------------- 1 | # Invalid Tweets 2 | 3 | ## Problem Statement 4 | Write a Pandas query to find the IDs of tweets whose content length exceeds 140 characters in the `Tweets` table. 5 | 6 | **Table: Tweets** 7 | ``` 8 | +----------------+---------+ 9 | | Column Name | Type | 10 | +----------------+---------+ 11 | | tweet_id | int | 12 | | content | varchar | 13 | +----------------+---------+ 14 | tweet_id is the primary key. 15 | ``` 16 | 17 | **Example**: 18 | - Input: `[[1, "Vote for Biden"], [2, "Let us make America great again!"]]` 19 | - Output: `[[2]]` 20 | 21 | **Constraints**: 22 | - `1 <= Tweets.tweet_id <= 10^5` 23 | - `0 <= Tweets.content.length <= 10^4` 24 | 25 | ## Solution 26 | ```python 27 | import pandas as pd 28 | 29 | def invalid_tweets(tweets: pd.DataFrame) -> pd.DataFrame: 30 | return tweets[tweets['content'].str.len() > 140][['tweet_id']] 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use `str.len()` to compute the length of each tweet’s `content`. Filter rows where length > 140 using boolean indexing. Return only the `tweet_id` column. 35 | - **Why str.len()?**: Pandas’ string method is vectorized, efficiently computing lengths for all rows. 36 | - **Edge Cases**: 37 | - No invalid tweets: Returns empty DataFrame. 38 | - Empty content: Length is 0, so not selected. 39 | - Single tweet: Returns one row if invalid. 40 | - **Optimizations**: Vectorized `str.len()` avoids loops; select only `tweet_id` for minimal output. 41 | 42 | ## Performance Analysis 43 | - **Time Complexity**: O(n), where n is the number of rows in `tweets`, for vectorized string length calculation and filtering. 44 | - **Space Complexity**: O(k), where k is the number of rows in the output DataFrame. 45 | - **Pandas Efficiency**: `str.len()` is optimized for string operations; boolean indexing is fast. 46 | 47 | ## Best Practices 48 | - Use vectorized string methods (`str.len()`). 49 | - Select only required columns (`tweet_id`). 50 | - Avoid loops for filtering. 51 | - Follow PEP 8 for Python code style. 52 | 53 | ## Alternative Approaches 54 | - **Apply**: Use `tweets[tweets['content'].apply(len) > 140][['tweet_id']]` (O(n), less efficient due to non-vectorized `apply`). 55 | - **Query Method**: Use `tweets.query('content.str.len() > 140')[['tweet_id']]` (similar performance, less explicit). -------------------------------------------------------------------------------- /Java/Arrays/Easy/single_number.md: -------------------------------------------------------------------------------- 1 | # Single Number 2 | 3 | ## Problem Statement 4 | Given a non-empty array of integers `nums`, every element appears twice except for one. Find that single one. You must implement a solution with a linear runtime complexity and use only constant extra space. 5 | 6 | **Example**: 7 | - Input: `nums = [2,2,1]` 8 | - Output: `1` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 3 * 10^4` 12 | - `-3 * 10^4 <= nums[i] <= 3 * 10^4` 13 | - Each element appears twice except for one element which appears once. 14 | 15 | ## Solution 16 | 17 | ### Java 18 | ```java 19 | class Solution { 20 | public int singleNumber(int[] nums) { 21 | int result = 0; 22 | for (int num : nums) { 23 | result ^= num; 24 | } 25 | return result; 26 | } 27 | } 28 | ``` 29 | 30 | ## Reasoning 31 | - **Approach**: Use XOR bitwise operation. XOR of a number with itself is 0, and XOR of a number with 0 is the number itself. Since all numbers except one appear twice, XORing all elements cancels out pairs, leaving the single number. 32 | - **Why XOR?**: It meets the requirement for O(n) time and O(1) space, as it processes each element once without extra storage. 33 | - **Edge Cases**: 34 | - Single element: Returns that element. 35 | - All pairs except one: XOR correctly isolates the single number. 36 | - **Optimizations**: Single pass with a single variable; no additional data structures needed. 37 | 38 | ## Complexity Analysis 39 | - **Time Complexity**: O(n), where n is the length of `nums`. Single pass through the array. 40 | - **Space Complexity**: O(1), as only one variable is used. 41 | 42 | ## Best Practices 43 | - Use clear variable names (e.g., `result` for XOR accumulator). 44 | - For Python, include type hints for clarity. 45 | - For JavaScript, use `for...of` for readable iteration. 46 | - For Java, follow Google Java Style Guide. 47 | - Leverage XOR’s properties for elegant, efficient solutions. 48 | 49 | ## Alternative Approaches 50 | - **Hash Set**: Store elements in a set, removing duplicates (O(n) time, O(n) space). Violates constant space requirement. 51 | - **Hash Map**: Count frequencies and find the element with count 1 (O(n) time, O(n) space). Also violates space constraint. 52 | - **Sorting**: Sort and find the unpaired element (O(n log n) time, O(1) space). Slower than XOR. -------------------------------------------------------------------------------- /JavaScript/Linked_Lists/Medium/remove_nth_node.md: -------------------------------------------------------------------------------- 1 | # Remove Nth Node From End of List 2 | 3 | ## Problem Statement 4 | Given the head of a linked list, remove the nth node from the end and return the head. 5 | 6 | **Example**: 7 | - Input: `head = [1,2,3,4,5], n = 2` 8 | - Output: `[1,2,3,5]` 9 | 10 | **Constraints**: 11 | - The number of nodes in the list is `sz`. 12 | - `1 <= sz <= 30` 13 | - `0 <= Node.val <= 100` 14 | - `1 <= n <= sz` 15 | 16 | ## Solution 17 | 18 | ### JavaScript 19 | ```javascript 20 | function ListNode(val, next) { 21 | this.val = (val === undefined ? 0 : val); 22 | this.next = (next === undefined ? null : next); 23 | } 24 | 25 | function removeNthFromEnd(head, n) { 26 | const dummy = new ListNode(0, head); 27 | let slow = dummy, fast = dummy; 28 | 29 | for (let i = 0; i <= n; i++) { 30 | fast = fast.next; 31 | } 32 | 33 | while (fast) { 34 | slow = slow.next; 35 | fast = fast.next; 36 | } 37 | 38 | slow.next = slow.next.next; 39 | return dummy.next; 40 | } 41 | ``` 42 | 43 | ## Reasoning 44 | - **Approach**: Use two pointers (slow and fast). Move fast n+1 steps ahead, then move both pointers until fast reaches the end. Slow will be just before the node to remove. Adjust the next pointer to skip the nth node. 45 | - **Why Two Pointers?**: Allows finding the nth node from the end in one pass without counting the list length. 46 | - **Edge Cases**: 47 | - Remove head: Use dummy node to simplify. 48 | - Single node: Return null if n=1. 49 | - **Optimizations**: Dummy node handles head removal; single pass for efficiency. 50 | 51 | ## Complexity Analysis 52 | - **Time Complexity**: O(n), where n is the number of nodes, as we traverse the list once. 53 | - **Space Complexity**: O(1), as we only use two pointers and a dummy node. 54 | 55 | ## Best Practices 56 | - Use clear variable names (e.g., `slow`, `fast`). 57 | - For Python, use type hints for clarity. 58 | - For JavaScript, use concise loop constructs. 59 | - For Java, follow Google Java Style Guide. 60 | - Use dummy node to handle edge cases. 61 | 62 | ## Alternative Approaches 63 | - **Two Passes**: Count list length, then traverse to remove node (O(n) time, O(1) space). Less efficient. 64 | - **Stack-Based**: Store nodes in a stack, pop n times (O(n) time, O(n) space). Less space-efficient. -------------------------------------------------------------------------------- /Java/Trees/Easy/symmetric_tree.md: -------------------------------------------------------------------------------- 1 | # Symmetric Tree 2 | 3 | ## Problem Statement 4 | Given the root of a binary tree, check whether it is a mirror of itself (i.e., symmetric around its center). 5 | 6 | **Example**: 7 | - Input: `root = [1,2,2,3,4,4,3]` 8 | - Output: `true` 9 | 10 | **Constraints**: 11 | - The number of nodes is in the range `[1, 1000]`. 12 | - `-100 <= Node.val <= 100` 13 | 14 | ## Solution 15 | 16 | ### Java 17 | ```java 18 | class Solution { 19 | public boolean isSymmetric(TreeNode root) { 20 | return isMirror(root, root); 21 | } 22 | 23 | private boolean isMirror(TreeNode left, TreeNode right) { 24 | if (left == null && right == null) return true; 25 | if (left == null || right == null) return false; 26 | return (left.val == right.val && 27 | isMirror(left.left, right.right) && 28 | isMirror(left.right, right.left)); 29 | } 30 | } 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use recursive mirror checking. Compare the left and right subtrees of the root, ensuring left’s left matches right’s right and left’s right matches right’s left. Check node values and recurse symmetrically. 35 | - **Why Recursive?**: Symmetry checking naturally compares mirrored subtrees, making recursion intuitive and concise. 36 | - **Edge Cases**: 37 | - Single node: Symmetric (true). 38 | - Empty tree: Handled by constraints (non-empty). 39 | - Unbalanced subtrees: Return false. 40 | - **Optimizations**: Recursive solution is clean; iterative possible but more complex. 41 | 42 | ## Complexity Analysis 43 | - **Time Complexity**: O(n), where n is the number of nodes, as each node is visited once. 44 | - **Space Complexity**: O(h), where h is the height of the tree, due to the recursion stack (O(n) in worst case for skewed tree). 45 | 46 | ## Best Practices 47 | - Use clear variable names (e.g., `left`, `right`). 48 | - For Python, use type hints and helper function. 49 | - For JavaScript, use strict equality (`===`). 50 | - For Java, follow Google Java Style Guide. 51 | - Ensure symmetric recursion for clarity. 52 | 53 | ## Alternative Approaches 54 | - **Iterative**: Use a queue to compare nodes level-by-level (O(n) time, O(w) space, where w is max width). More complex. 55 | - **BFS with Mirroring**: Compare level arrays (O(n) time, O(n) space). Less efficient. -------------------------------------------------------------------------------- /JavaScript/Dynamic_Programming/Medium/longest_increasing_subsequence.md: -------------------------------------------------------------------------------- 1 | # Longest Increasing Subsequence 2 | 3 | ## Problem Statement 4 | Given an integer array `nums`, return the length of the longest strictly increasing subsequence. 5 | 6 | **Example**: 7 | - Input: `nums = [10,9,2,5,3,7,101,18]` 8 | - Output: `4` 9 | - Explanation: The longest increasing subsequence is `[2,3,7,101]`, with length 4. 10 | 11 | **Constraints**: 12 | - `1 <= nums.length <= 2500` 13 | - `-10^4 <= nums[i] <= 10^4` 14 | 15 | ## Solution 16 | 17 | ### JavaScript 18 | ```javascript 19 | function lengthOfLIS(nums) { 20 | if (!nums.length) return 0; 21 | const dp = new Array(nums.length).fill(1); 22 | for (let i = 1; i < nums.length; i++) { 23 | for (let j = 0; j < i; j++) { 24 | if (nums[i] > nums[j]) { 25 | dp[i] = Math.max(dp[i], dp[j] + 1); 26 | } 27 | } 28 | } 29 | return Math.max(...dp); 30 | } 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use dynamic programming where `dp[i]` represents the length of the longest increasing subsequence ending at index `i`. For each `i`, check all previous indices `j` where `nums[i] > nums[j]` and update `dp[i] = max(dp[i], dp[j] + 1)`. Return the maximum value in `dp`. 35 | - **Why DP?**: Avoids recomputing subsequences by storing lengths for each ending index. 36 | - **Edge Cases**: 37 | - Empty array: Return 0. 38 | - Single element: Return 1. 39 | - **Optimizations**: Use a simple array; can optimize to O(n log n) with binary search (not shown here for simplicity). 40 | 41 | ## Complexity Analysis 42 | - **Time Complexity**: O(n^2), where n is the length of `nums`, due to nested loops. 43 | - **Space Complexity**: O(n) for the DP array. 44 | 45 | ## Best Practices 46 | - Use clear variable names (e.g., `dp` for dynamic programming array). 47 | - For Python, use type hints for clarity. 48 | - For JavaScript, use array methods for readability. 49 | - For Java, use `Arrays.fill` and follow Google Java Style Guide. 50 | - Initialize `dp` with 1s since each element is a subsequence of length 1. 51 | 52 | ## Alternative Approaches 53 | - **Binary Search**: Maintain an active list of subsequence ends (O(n log n) time, O(n) space). More complex. 54 | - **Recursion with Memoization**: Cache results (O(n^2) time, O(n^2) space). Less efficient than iterative. -------------------------------------------------------------------------------- /JavaScript/Sorting_Searching/Medium/sort_colors.md: -------------------------------------------------------------------------------- 1 | # Sort Colors 2 | 3 | ## Problem Statement 4 | Given an array `nums` with n objects colored 0, 1, or 2, sort them in-place so that objects of the same color are adjacent, with the colors in the order 0, 1, and 2. 5 | 6 | **Example**: 7 | - Input: `nums = [2,0,2,1,1,0]` 8 | - Output: `[0,0,1,1,2,2]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 300` 12 | - `nums[i]` is 0, 1, or 2. 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | function sortColors(nums) { 19 | let low = 0, mid = 0, high = nums.length - 1; 20 | 21 | while (mid <= high) { 22 | if (nums[mid] === 0) { 23 | [nums[low], nums[mid]] = [nums[mid], nums[low]]; 24 | low++; 25 | mid++; 26 | } else if (nums[mid] === 1) { 27 | mid++; 28 | } else { 29 | [nums[mid], nums[high]] = [nums[high], nums[mid]]; 30 | high--; 31 | } 32 | } 33 | } 34 | ``` 35 | 36 | ## Reasoning 37 | - **Approach**: Use the Dutch National Flag algorithm with three pointers: `low` for 0s, `mid` for 1s, and `high` for 2s. Swap elements to place 0s before `low`, 1s between `low` and `high`, and 2s after `high`. Move pointers based on `nums[mid]`. 38 | - **Why Dutch National Flag?**: Sorts three distinct values in one pass with O(1) space. 39 | - **Edge Cases**: 40 | - Single element: Already sorted. 41 | - All same value: Algorithm handles efficiently. 42 | - Small array: Works correctly. 43 | - **Optimizations**: In-place sorting; single pass with three pointers. 44 | 45 | ## Complexity Analysis 46 | - **Time Complexity**: O(n), where n is the length of `nums`, as we traverse the array once. 47 | - **Space Complexity**: O(1), as we sort in-place using only pointers. 48 | 49 | ## Best Practices 50 | - Use clear variable names (e.g., `low`, `mid`, `high`). 51 | - For Python, use type hints and tuple unpacking for swaps. 52 | - For JavaScript, use array destructuring for swaps. 53 | - For Java, follow Google Java Style Guide and use explicit swaps. 54 | - Optimize with single-pass algorithm. 55 | 56 | ## Alternative Approaches 57 | - **Counting Sort**: Count 0s, 1s, 2s, then rewrite array (O(n) time, O(1) space). Two passes, less elegant. 58 | - **Standard Sort**: Use built-in sort (O(n log n) time). Overkill for three values. -------------------------------------------------------------------------------- /Python/Sorting_Searching/Hard/find_minimum_in_rotated_sorted_array_ii.markdown: -------------------------------------------------------------------------------- 1 | # Find Minimum in Rotated Sorted Array II 2 | 3 | ## Problem Statement 4 | Given a sorted array `nums` rotated at some pivot, with possible duplicates, find the minimum element. The algorithm must run in O(log n) time in the average case. 5 | 6 | **Example**: 7 | - Input: `nums = [2,2,2,0,1]` 8 | - Output: `0` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 5000` 12 | - `-5000 <= nums[i] <= 5000` 13 | - `nums` is sorted and rotated, with possible duplicates. 14 | 15 | ## Solution 16 | 17 | ### Python 18 | ```python 19 | def findMin(nums: list[int]) -> int: 20 | left, right = 0, len(nums) - 1 21 | 22 | while left < right: 23 | mid = (left + right) // 2 24 | if nums[mid] > nums[right]: 25 | left = mid + 1 26 | elif nums[mid] < nums[right]: 27 | right = mid 28 | else: 29 | right -= 1 30 | 31 | return nums[left] 32 | ``` 33 | 34 | ## Reasoning 35 | - **Approach**: Use binary search, comparing `nums[mid]` with `nums[right]`. If greater, minimum is in right half; if less, minimum is in left half including mid; if equal, exclude rightmost element due to duplicates. Converge to the minimum. 36 | - **Why Binary Search?**: Handles rotation and duplicates, aiming for O(log n) average time, though worst case is O(n) with many duplicates. 37 | - **Edge Cases**: 38 | - Single element: Return it. 39 | - All duplicates: Linear scan in worst case. 40 | - No rotation: Minimum at index 0. 41 | - **Optimizations**: Use `right--` to handle duplicates; avoid overflow with midpoint calculation. 42 | 43 | ## Complexity Analysis 44 | - **Time Complexity**: O(log n) average, O(n) worst case (all duplicates). 45 | - **Space Complexity**: O(1), as only a few variables are used. 46 | 47 | ## Best Practices 48 | - Use clear variable names (e.g., `left`, `right`). 49 | - For Python, use type hints. 50 | - For JavaScript, use `Math.floor` for integer division. 51 | - For Java, follow Google Java Style Guide and use overflow-safe midpoint. 52 | - Handle duplicates by excluding rightmost element. 53 | 54 | ## Alternative Approaches 55 | - **Linear Scan**: Find minimum by iteration (O(n) time). Too slow. 56 | - **Find Pivot**: Locate rotation point, then take next element (O(log n) average). Similar complexity. -------------------------------------------------------------------------------- /JavaScript/Dynamic_Programming/Easy/house_robber.md: -------------------------------------------------------------------------------- 1 | # House Robber 2 | 3 | ## Problem Statement 4 | You are a robber planning to rob houses along a street. Each house has a certain amount of money, represented by `nums`. You cannot rob adjacent houses. Return the maximum amount you can rob without alerting the police. 5 | 6 | **Example**: 7 | - Input: `nums = [1,2,3,1]` 8 | - Output: `4` 9 | - Explanation: Rob house 1 (1) and house 3 (3) for a total of 4. 10 | 11 | **Constraints**: 12 | - `0 <= nums.length <= 100` 13 | - `0 <= nums[i] <= 400` 14 | 15 | ## Solution 16 | 17 | ### JavaScript 18 | ```javascript 19 | function rob(nums) { 20 | if (!nums.length) return 0; 21 | if (nums.length <= 2) return Math.max(...nums); 22 | const dp = new Array(nums.length).fill(0); 23 | dp[0] = nums[0]; 24 | dp[1] = Math.max(nums[0], nums[1]); 25 | for (let i = 2; i < nums.length; i++) { 26 | dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]); 27 | } 28 | return dp[dp.length - 1]; 29 | } 30 | ``` 31 | 32 | ## Reasoning 33 | - **Approach**: Use dynamic programming to track the maximum loot up to each house. For house `i`, either skip it (`dp[i-1]`) or rob it and skip the previous house (`dp[i-2] + nums[i]`). Thus, `dp[i] = max(dp[i-1], dp[i-2] + nums[i])`. 34 | - **Why DP?**: Avoids recomputing subproblems by storing maximum loot for each prefix. 35 | - **Edge Cases**: 36 | - Empty array: Return 0. 37 | - One or two houses: Return maximum value. 38 | - **Optimizations**: Use array-based DP; can optimize to O(1) space with two variables. 39 | 40 | ## Complexity Analysis 41 | - **Time Complexity**: O(n), single loop through the array. 42 | - **Space Complexity**: O(n) for the DP array. Can be optimized to O(1) using two variables. 43 | 44 | ## Best Practices 45 | - Use clear variable names (e.g., `dp` for dynamic programming array). 46 | - For Python, use type hints and handle edge cases. 47 | - For JavaScript, use spread operator for max in small arrays. 48 | - For Java, follow Google Java Style Guide. 49 | - Handle edge cases early for efficiency. 50 | 51 | ## Alternative Approaches 52 | - **Optimized Space DP**: Use two variables (O(n) time, O(1) space). 53 | - **Recursion with Memoization**: Cache results (O(n) time, O(n) space). Less efficient than iterative. 54 | - **Brute Force**: Try all valid combinations (O(2^(n/2)) time). Too slow. -------------------------------------------------------------------------------- /JavaScript/Arrays/Hard/maximum_subarray_product.md: -------------------------------------------------------------------------------- 1 | # Maximum Subarray Product 2 | 3 | ## Problem Statement 4 | Given an integer array `nums`, find a contiguous non-empty subarray with the largest product, and return that product. 5 | 6 | **Example**: 7 | - Input: `nums = [2,3,-2,4]` 8 | - Output: `6` 9 | - Explanation: Subarray `[2,3]` has the largest product `6`. 10 | 11 | **Constraints**: 12 | - `1 <= nums.length <= 2 * 10^4` 13 | - `-10 <= nums[i] <= 10` 14 | - The product of any subarray is guaranteed to fit in a 32-bit integer. 15 | 16 | ## Solution 17 | 18 | ### JavaScript 19 | ```javascript 20 | function maxProduct(nums) { 21 | let maxSoFar = nums[0], minSoFar = nums[0], result = nums[0]; 22 | for (let i = 1; i < nums.length; i++) { 23 | const tempMax = Math.max(nums[i], maxSoFar * nums[i], minSoFar * nums[i]); 24 | minSoFar = Math.min(nums[i], maxSoFar * nums[i], minSoFar * nums[i]); 25 | maxSoFar = tempMax; 26 | result = Math.max(result, maxSoFar); 27 | } 28 | return result; 29 | } 30 | ``` 31 | 32 | ## Reasoning 33 | - **Approach**: Track maximum and minimum products ending at each index, as a negative number can turn a minimum product into a maximum with another negative number. Update `max_so_far`, `min_so_far`, and global `result` at each step. 34 | - **Why Track Min?**: Negative numbers can flip maximum to minimum products, so we need both. 35 | - **Edge Cases**: 36 | - Single element: Return that element. 37 | - Zeros: Reset product, consider single numbers. 38 | - All negatives: Maximum might be a single number or product of two negatives. 39 | - **Optimizations**: Single pass; constant space. 40 | 41 | ## Complexity Analysis 42 | - **Time Complexity**: O(n), where n is the length of `nums`. Single pass through the array. 43 | - **Space Complexity**: O(1), using only constant space. 44 | 45 | ## Best Practices 46 | - Use clear variable names (e.g., `max_so_far`, `min_so_far`). 47 | - For Python, use type hints for clarity. 48 | - For JavaScript, use `Math.max/min` for readability. 49 | - For Java, follow Google Java Style Guide. 50 | - Track both max and min products to handle negative numbers. 51 | 52 | ## Alternative Approaches 53 | - **Brute Force**: Check all subarrays (O(n²) time). Inefficient. 54 | - **Divide and Conquer**: Split array and compute max product (O(n log n) time). Too complex. -------------------------------------------------------------------------------- /JavaScript/Arrays/Medium/container_with_most_water.md: -------------------------------------------------------------------------------- 1 | # Container With Most Water 2 | 3 | ## Problem Statement 4 | Given an integer array `height` of length `n`, find two lines that, together with the x-axis, form a container with the most water. Return the maximum area. 5 | 6 | **Example**: 7 | - Input: `height = [1,8,6,2,5,4,8,3,7]` 8 | - Output: `49` 9 | - Explanation: The container formed by indices 1 and 8 (heights 8 and 7) has area `7 * (8-1) = 49`. 10 | 11 | **Constraints**: 12 | - `n == height.length` 13 | - `2 <= n <= 10^5` 14 | - `0 <= height[i] <= 10^4` 15 | 16 | ## Solution 17 | 18 | ### JavaScript 19 | ```javascript 20 | function maxArea(height) { 21 | let left = 0, right = height.length - 1; 22 | let maxArea = 0; 23 | while (left < right) { 24 | const width = right - left; 25 | maxArea = Math.max(maxArea, Math.min(height[left], height[right]) * width); 26 | if (height[left] < height[right]) { 27 | left++; 28 | } else { 29 | right--; 30 | } 31 | } 32 | return maxArea; 33 | } 34 | ``` 35 | 36 | ## Reasoning 37 | - **Approach**: Use two pointers (left, right) starting at array ends. Compute area as `min(height[left], height[right]) * (right - left)`. Move the pointer with the smaller height inward to maximize potential area. 38 | - **Why Two Pointers?**: Moving the smaller height maximizes area potential, as width decreases but height might increase. 39 | - **Edge Cases**: 40 | - Two elements: Compute single area. 41 | - All equal heights: Handled by moving either pointer. 42 | - **Optimizations**: Single pass with two pointers; no extra space needed. 43 | 44 | ## Complexity Analysis 45 | - **Time Complexity**: O(n), where n is the length of `height`. Single pass with two pointers. 46 | - **Space Complexity**: O(1), using only constant space. 47 | 48 | ## Best Practices 49 | - Use clear variable names (e.g., `left`, `right`, `max_area`). 50 | - For Python, use type hints for clarity. 51 | - For JavaScript, use `Math.min/max` for readability. 52 | - For Java, follow Google Java Style Guide. 53 | - Move smaller height to optimize area calculation. 54 | 55 | ## Alternative Approaches 56 | - **Brute Force**: Check all pairs of lines (O(n²) time). Inefficient for large inputs. 57 | - **Greedy with Sorting**: Sort heights and try combinations (O(n log n) time). Less efficient. -------------------------------------------------------------------------------- /Python/Arrays/Medium/group_anagrams.md: -------------------------------------------------------------------------------- 1 | # Group Anagrams 2 | 3 | ## Problem Statement 4 | Given an array of strings `strs`, group the anagrams together. You can return the answer in any order. An anagram is a word formed by rearranging the letters of another. 5 | 6 | **Example**: 7 | - Input: `strs = ["eat","tea","tan","ate","nat","bat"]` 8 | - Output: `[["bat"],["nat","tan"],["ate","eat","tea"]]` 9 | 10 | **Constraints**: 11 | - `1 <= strs.length <= 10^4` 12 | - `0 <= strs[i].length <= 100` 13 | - `strs[i]` consists of lowercase English letters. 14 | 15 | ## Solution 16 | 17 | ### Python 18 | ```python 19 | from collections import defaultdict 20 | 21 | def groupAnagrams(strs: list[str]) -> list[list[str]]: 22 | anagram_map = defaultdict(list) 23 | for s in strs: 24 | key = ''.join(sorted(s)) 25 | anagram_map[key].append(s) 26 | return list(anagram_map.values()) 27 | ``` 28 | 29 | ## Reasoning 30 | - **Approach**: Use a hash map to group strings by their sorted characters (key). Each key maps to a list of anagrams. Sorting characters ensures anagrams have the same key. 31 | - **Why Sorted Key?**: Sorting characters is a reliable way to identify anagrams, as all anagrams share the same sorted string. 32 | - **Edge Cases**: 33 | - Empty array: Return empty list. 34 | - Single string: Return a list with one group. 35 | - Empty strings: Treated as anagrams of each other. 36 | - **Optimizations**: Use `defaultdict` in Python for concise code; `computeIfAbsent` in Java for efficient map updates. 37 | 38 | ## Complexity Analysis 39 | - **Time Complexity**: O(n * k * log k), where n is the number of strings and k is the maximum string length (due to sorting each string). 40 | - **Space Complexity**: O(n * k) for the hash map and output. 41 | 42 | ## Best Practices 43 | - Use clear variable names (e.g., `anagram_map`, `key`). 44 | - For Python, use `defaultdict` to simplify map operations. 45 | - For JavaScript, use `Map` for key-value pairs. 46 | - For Java, use `computeIfAbsent` and follow Google Java Style Guide. 47 | - Sort characters to create a consistent anagram key. 48 | 49 | ## Alternative Approaches 50 | - **Character Count Key**: Use a frequency array or string (e.g., `"a1b2"`) as the key (O(n * k) time, O(n * k) space). Faster for small alphabets. 51 | - **Brute Force**: Compare each string with others (O(n² * k) time). Inefficient. -------------------------------------------------------------------------------- /Java/Linked_Lists/Medium/swap_nodes_in_pairs.md: -------------------------------------------------------------------------------- 1 | # Swap Nodes in Pairs 2 | 3 | ## Problem Statement 4 | Given a linked list, swap every two adjacent nodes and return its head. You must solve the problem without modifying the values in the nodes (only nodes themselves may be changed). 5 | 6 | **Example**: 7 | - Input: `head = [1,2,3,4]` 8 | - Output: `[2,1,4,3]` 9 | 10 | **Constraints**: 11 | - The number of nodes in the list is in the range `[0, 100]`. 12 | - `0 <= Node.val <= 100` 13 | 14 | ## Solution 15 | 16 | ### Java 17 | ```java 18 | class ListNode { 19 | int val; 20 | ListNode next; 21 | ListNode(int val) { this.val = val; } 22 | ListNode(int val, ListNode next) { this.val = val; this.next = next; } 23 | } 24 | 25 | class Solution { 26 | public ListNode swapPairs(ListNode head) { 27 | if (head == null || head.next == null) return head; 28 | 29 | ListNode nextNode = head.next; 30 | head.next = swapPairs(nextNode.next); 31 | nextNode.next = head; 32 | return nextNode; 33 | } 34 | } 35 | ``` 36 | 37 | ## Reasoning 38 | - **Approach**: Use recursion to swap pairs. For each pair, swap the current node with the next, recursively swap the rest of the list, and connect the swapped pair. Base case: return if list is empty or has one node. 39 | - **Why Recursive?**: Simplifies swapping logic by handling pairs recursively, ensuring clean pointer updates. 40 | - **Edge Cases**: 41 | - Empty list or single node: Return as is. 42 | - Odd number of nodes: Last node remains unswapped. 43 | - **Optimizations**: Recursive approach is concise; no extra space except recursion stack. 44 | 45 | ## Complexity Analysis 46 | - **Time Complexity**: O(n), where n is the number of nodes, as we process each node once. 47 | - **Space Complexity**: O(n) due to the recursion stack for n/2 recursive calls. 48 | 49 | ## Best Practices 50 | - Use clear variable names (e.g., `nextNode`). 51 | - For Python, use type hints for clarity. 52 | - For JavaScript, use concise null checks. 53 | - For Java, follow Google Java Style Guide. 54 | - Handle base cases early. 55 | 56 | ## Alternative Approaches 57 | - **Iterative**: Use pointers to swap pairs in-place (O(n) time, O(1) space). More complex but space-efficient. 58 | - **Dummy Node Iterative**: Use a dummy node to simplify iterative swapping (O(n) time, O(1) space). Slightly clearer. -------------------------------------------------------------------------------- /Python/Arrays/Hard/trapping_rain_water.md: -------------------------------------------------------------------------------- 1 | # Trapping Rain Water 2 | 3 | ## Problem Statement 4 | Given an array `height` of non-negative integers representing an elevation map, compute how much water it can trap after raining. 5 | 6 | **Example**: 7 | - Input: `height = [0,1,0,2,1,0,1,3,2,1,2,1]` 8 | - Output: `6` 9 | - Explanation: The elevation map traps 6 units of water. 10 | 11 | **Constraints**: 12 | - `n == height.length` 13 | - `1 <= n <= 2 * 10^4` 14 | - `0 <= height[i] <= 10^5` 15 | 16 | ## Solution 17 | 18 | ### Python 19 | ```python 20 | def trap(height: list[int]) -> int: 21 | left, right = 0, len(height) - 1 22 | left_max = right_max = water = 0 23 | while left < right: 24 | if height[left] < height[right]: 25 | left_max = max(left_max, height[left]) 26 | water += left_max - height[left] 27 | left += 1 28 | else: 29 | right_max = max(right_max, height[right]) 30 | water += right_max - height[right] 31 | right -= 1 32 | return water 33 | ``` 34 | 35 | ## Reasoning 36 | - **Approach**: Use two pointers to track maximum heights from left and right. Water trapped at each position is the minimum of `left_max` and `right_max` minus the current height. Move the pointer from the smaller height side to ensure correct water calculation. 37 | - **Why Two Pointers?**: Avoids computing max heights for each position separately, achieving O(n) time with O(1) space. 38 | - **Edge Cases**: 39 | - Single element: No water trapped. 40 | - Monotonic array: No water trapped. 41 | - **Optimizations**: Single pass with two pointers; no extra arrays needed. 42 | 43 | ## Complexity Analysis 44 | - **Time Complexity**: O(n), where n is the length of `height`. Single pass with two pointers. 45 | - **Space Complexity**: O(1), using only constant space. 46 | 47 | ## Best Practices 48 | - Use clear variable names (e.g., `left_max`, `right_max`). 49 | - For Python, use type hints for clarity. 50 | - For JavaScript, use `Math.max` for readability. 51 | - For Java, follow Google Java Style Guide. 52 | - Process smaller height side to optimize water calculation. 53 | 54 | ## Alternative Approaches 55 | - **Two Arrays**: Store left and right max heights (O(n) time, O(n) space). Uses more space. 56 | - **Brute Force**: Compute min(left_max, right_max) for each index (O(n²) time). Inefficient. -------------------------------------------------------------------------------- /Python/Backtracking/Medium/subsets_ii.md: -------------------------------------------------------------------------------- 1 | # Subsets II 2 | 3 | ## Problem Statement 4 | Given an integer array `nums` that may contain duplicates, return all possible unique subsets (the power set). The solution set must not contain duplicate subsets. Return the answer in any order. 5 | 6 | **Example**: 7 | - Input: `nums = [1,2,2]` 8 | - Output: `[[],[1],[1,2],[1,2,2],[2],[2,2]]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 10` 12 | - `-10 <= nums[i] <= 10` 13 | 14 | ## Solution 15 | 16 | ### Python 17 | ```python 18 | def subsetsWithDup(nums: list[int]) -> list[list[int]]: 19 | nums.sort() 20 | result = [] 21 | 22 | def backtrack(index: int, current: list[int]) -> None: 23 | result.append(current[:]) 24 | for i in range(index, len(nums)): 25 | if i > index and nums[i] == nums[i - 1]: 26 | continue 27 | current.append(nums[i]) 28 | backtrack(i + 1, current) 29 | current.pop() 30 | 31 | backtrack(0, []) 32 | return result 33 | ``` 34 | 35 | ## Reasoning 36 | - **Approach**: Sort the array to group duplicates, then use backtracking to generate subsets. Skip duplicate elements at the same level to avoid duplicate subsets. Add each subset to the result. 37 | - **Why Sort?**: Sorting ensures duplicates are adjacent, making it easier to skip them. 38 | - **Edge Cases**: 39 | - Empty array: Return `[[]]`. 40 | - All duplicates: Generate unique subsets (e.g., `[1,1]` → `[[],[1],[1,1]]`). 41 | - **Optimizations**: Skip duplicates at the same recursion level; copy current list to avoid reference issues. 42 | 43 | ## Complexity Analysis 44 | - **Time Complexity**: O(2^n), where n is the length of `nums`, as there are up to 2^n subsets. Sorting takes O(n log n). 45 | - **Space Complexity**: O(n) for the recursion stack, plus O(2^n) for the output. 46 | 47 | ## Best Practices 48 | - Use clear variable names (e.g., `index`, `current`). 49 | - For Python, use type hints and sorting. 50 | - For JavaScript, use spread operator and sorting. 51 | - For Java, use `Arrays.sort` and follow Google Java Style Guide. 52 | - Skip duplicates to ensure unique subsets. 53 | 54 | ## Alternative Approaches 55 | - **Bit Manipulation**: Use binary numbers with duplicate handling (O(2^n) time). More complex. 56 | - **Iterative**: Build subsets iteratively (same complexity). Less intuitive. -------------------------------------------------------------------------------- /JavaScript/Arrays/Easy/majority_element.md: -------------------------------------------------------------------------------- 1 | # Majority Element 2 | 3 | ## Problem Statement 4 | Given an array `nums` of size `n`, return the majority element. The majority element is the element that appears more than `⌊n/2⌋` times. You may assume the majority element always exists. 5 | 6 | **Example**: 7 | - Input: `nums = [2,2,1,1,1,2,2]` 8 | - Output: `2` 9 | - Explanation: `2` appears 4 times, which is more than `n/2 = 3.5`. 10 | 11 | **Constraints**: 12 | - `1 <= nums.length <= 5 * 10^4` 13 | - `-10^9 <= nums[i] <= 10^9` 14 | 15 | ## Solution 16 | 17 | ### JavaScript 18 | ```javascript 19 | function majorityElement(nums) { 20 | let count = 0; 21 | let candidate = 0; 22 | for (const num of nums) { 23 | if (count === 0) { 24 | candidate = num; 25 | } 26 | count += (num === candidate ? 1 : -1); 27 | } 28 | return candidate; 29 | } 30 | ``` 31 | 32 | ## Reasoning 33 | - **Approach**: Use Boyer-Moore Voting Algorithm. Since the majority element appears more than `n/2` times, maintain a candidate and count. Increment count when seeing the candidate, decrement otherwise. When count reaches 0, pick a new candidate. The final candidate is the majority element. 34 | - **Why Boyer-Moore?**: It guarantees the majority element in a single pass without extra space, leveraging the fact that the majority element outweighs others. 35 | - **Edge Cases**: 36 | - Single element: Returns that element. 37 | - Majority element exists: Guaranteed by problem constraints. 38 | - **Optimizations**: Single pass with minimal variables; no need for validation due to problem assumptions. 39 | 40 | ## Complexity Analysis 41 | - **Time Complexity**: O(n), where n is the length of `nums`. Single pass through the array. 42 | - **Space Complexity**: O(1), as only two variables are used. 43 | 44 | ## Best Practices 45 | - Use clear variable names (e.g., `candidate`, `count`). 46 | - For Python, include type hints for clarity. 47 | - For JavaScript, use `for...of` for readability. 48 | - For Java, follow Google Java Style Guide. 49 | - Keep logic simple to leverage the algorithm’s elegance. 50 | 51 | ## Alternative Approaches 52 | - **Hash Map**: Count frequencies and return the element with count > `n/2` (O(n) time, O(n) space). 53 | - **Sorting**: Sort the array and return the middle element (O(n log n) time, O(1) space). Less efficient than Boyer-Moore. -------------------------------------------------------------------------------- /MySQL/Easy/second_highest_salary.md: -------------------------------------------------------------------------------- 1 | # Second Highest Salary 2 | 3 | ## Problem Statement 4 | Write a SQL query to report the second highest salary from the `Employee` table. If there is no second highest salary, return `null`. 5 | 6 | **Table: Employee** 7 | ``` 8 | +-------------+------+ 9 | | Column Name | Type | 10 | +-------------+------+ 11 | | id | int | 12 | | salary | int | 13 | +-------------+------+ 14 | id is the primary key. 15 | ``` 16 | 17 | **Example**: 18 | - Input: `[[1, 100], [2, 200], [3, 300]]` 19 | - Output: `200` 20 | - Input: `[[1, 100]]` 21 | - Output: `null` 22 | 23 | **Constraints**: 24 | - `1 <= Employee.id <= 10^5` 25 | - `0 <= Employee.salary <= 10^5` 26 | 27 | ## Solution 28 | ```sql 29 | SELECT MAX(salary) AS SecondHighestSalary 30 | FROM Employee 31 | WHERE salary < (SELECT MAX(salary) FROM Employee); 32 | ``` 33 | 34 | ## Reasoning 35 | - **Approach**: Find the maximum salary excluding the highest salary using a subquery. The outer query selects the maximum salary less than the highest salary. If no such salary exists, it returns `null`. 36 | - **Why Subquery?**: Allows filtering out the highest salary to find the next highest in a single query. 37 | - **Edge Cases**: 38 | - Single salary: Returns `null` (no second highest). 39 | - Duplicate salaries: Returns the second distinct highest salary. 40 | - Empty table: Handled by constraints (at least one row). 41 | - **Optimizations**: Simple subquery avoids sorting; leverages `MAX` for efficiency. 42 | 43 | ## Performance Analysis 44 | - **Time Complexity**: O(n) for each `MAX` operation, assuming a table scan (no index on `salary`). 45 | - **Space Complexity**: O(1), excluding output storage. 46 | - **Index Usage**: An index on `salary` could optimize `MAX` operations, but not strictly necessary for small datasets. 47 | 48 | ## Best Practices 49 | - Use clear column alias (`SecondHighestSalary`). 50 | - Avoid unnecessary sorting (e.g., `ORDER BY` with `LIMIT`). 51 | - Write concise subqueries for readability. 52 | - Format SQL consistently. 53 | 54 | ## Alternative Approaches 55 | - **LIMIT/OFFSET**: `SELECT DISTINCT salary FROM Employee ORDER BY salary DESC LIMIT 1 OFFSET 1` (O(n log n) due to sorting). 56 | - **Self-Join**: Join table with itself to find second highest (O(n^2), less efficient). 57 | - **DENSE_RANK**: Use window function (O(n log n), overkill for simple case). -------------------------------------------------------------------------------- /Python/Trees/Easy/symmetric_tree.md: -------------------------------------------------------------------------------- 1 | # Symmetric Tree 2 | 3 | ## Problem Statement 4 | Given the root of a binary tree, check whether it is a mirror of itself (i.e., symmetric around its center). 5 | 6 | **Example**: 7 | - Input: `root = [1,2,2,3,4,4,3]` 8 | - Output: `true` 9 | 10 | **Constraints**: 11 | - The number of nodes is in the range `[1, 1000]`. 12 | - `-100 <= Node.val <= 100` 13 | 14 | ## Solution 15 | 16 | ### Python 17 | ```python 18 | class Solution: 19 | def isSymmetric(self, root: TreeNode) -> bool: 20 | def isMirror(left: TreeNode, right: TreeNode) -> bool: 21 | if not left and not right: 22 | return True 23 | if not left or not right: 24 | return False 25 | return (left.val == right.val and 26 | isMirror(left.left, right.right) and 27 | isMirror(left.right, right.left)) 28 | 29 | return isMirror(root, root) 30 | ``` 31 | 32 | ## Reasoning 33 | - **Approach**: Use recursive mirror checking. Compare the left and right subtrees of the root, ensuring left’s left matches right’s right and left’s right matches right’s left. Check node values and recurse symmetrically. 34 | - **Why Recursive?**: Symmetry checking naturally compares mirrored subtrees, making recursion intuitive and concise. 35 | - **Edge Cases**: 36 | - Single node: Symmetric (true). 37 | - Empty tree: Handled by constraints (non-empty). 38 | - Unbalanced subtrees: Return false. 39 | - **Optimizations**: Recursive solution is clean; iterative possible but more complex. 40 | 41 | ## Complexity Analysis 42 | - **Time Complexity**: O(n), where n is the number of nodes, as each node is visited once. 43 | - **Space Complexity**: O(h), where h is the height of the tree, due to the recursion stack (O(n) in worst case for skewed tree). 44 | 45 | ## Best Practices 46 | - Use clear variable names (e.g., `left`, `right`). 47 | - For Python, use type hints and helper function. 48 | - For JavaScript, use strict equality (`===`). 49 | - For Java, follow Google Java Style Guide. 50 | - Ensure symmetric recursion for clarity. 51 | 52 | ## Alternative Approaches 53 | - **Iterative**: Use a queue to compare nodes level-by-level (O(n) time, O(w) space, where w is max width). More complex. 54 | - **BFS with Mirroring**: Compare level arrays (O(n) time, O(n) space). Less efficient. -------------------------------------------------------------------------------- /Java/Trees/Easy/binary_tree_inorder_traversal.md: -------------------------------------------------------------------------------- 1 | # Binary Tree Inorder Traversal 2 | 3 | ## Problem Statement 4 | Given the root of a binary tree, return the inorder traversal of its nodes' values (left, root, right). 5 | 6 | **Example**: 7 | - Input: `root = [1,null,2,3]` 8 | - Output: `[1,3,2]` 9 | 10 | **Constraints**: 11 | - The number of nodes is in the range `[0, 100]`. 12 | - `-100 <= Node.val <= 100` 13 | 14 | ## Solution 15 | 16 | ### Java 17 | ```java 18 | import java.util.*; 19 | 20 | class Solution { 21 | public List inorderTraversal(TreeNode root) { 22 | List result = new ArrayList<>(); 23 | inorder(root, result); 24 | return result; 25 | } 26 | 27 | private void inorder(TreeNode node, List result) { 28 | if (node == null) return; 29 | inorder(node.left, result); 30 | result.add(node.val); 31 | inorder(node.right, result); 32 | } 33 | } 34 | ``` 35 | 36 | ## Reasoning 37 | - **Approach**: Use recursive inorder traversal. Visit the left subtree, append the current node’s value, then visit the right subtree. Store results in a list. 38 | - **Why Recursive?**: Inorder traversal naturally follows a recursive pattern, ensuring correct order (left, root, right) with minimal code. 39 | - **Edge Cases**: 40 | - Empty tree: Return empty list. 41 | - Single node: Return [node.val]. 42 | - Skewed tree: Works like a linked list. 43 | - **Optimizations**: Recursive solution is clean and leverages call stack; iterative solution possible but more complex. 44 | 45 | ## Complexity Analysis 46 | - **Time Complexity**: O(n), where n is the number of nodes, as each node is visited once. 47 | - **Space Complexity**: O(h), where h is the height of the tree, due to the recursion stack (O(n) in worst case for skewed tree). 48 | 49 | ## Best Practices 50 | - Use clear variable names (e.g., `result`, `node`). 51 | - For Python, use type hints and helper function. 52 | - For JavaScript, use nested function for recursion. 53 | - For Java, use `List` and follow Google Java Style Guide. 54 | - Keep recursion simple for readability. 55 | 56 | ## Alternative Approaches 57 | - **Iterative**: Use a stack to mimic recursion (O(n) time, O(h) space). More complex but avoids recursion overhead. 58 | - **Morris Traversal**: Threaded binary tree approach (O(n) time, O(1) space). Advanced and less readable. -------------------------------------------------------------------------------- /Pandas/Easy/recyclable_and_low_fat_products.md: -------------------------------------------------------------------------------- 1 | # Recyclable and Low Fat Products 2 | 3 | ## Problem Statement 4 | Write a Pandas query to find the IDs of products that are both recyclable and low fat in the `Products` table. 5 | 6 | **Table: Products** 7 | ``` 8 | +-------------+---------+ 9 | | Column Name | Type | 10 | +-------------+---------+ 11 | | product_id | int | 12 | | low_fats | varchar | 13 | | recyclable | varchar | 14 | +-------------+---------+ 15 | product_id is the primary key. 16 | ``` 17 | 18 | **Example**: 19 | - Input: `[[0, "Y", "N"], [1, "Y", "Y"], [2, "N", "Y"], [3, "Y", "Y"], [4, "N", "N"]]` 20 | - Output: `[[1], [3]]` 21 | 22 | **Constraints**: 23 | - `1 <= Products.product_id <= 10^5` 24 | 25 | ## Solution 26 | ```python 27 | import pandas as pd 28 | 29 | def find_products(products: pd.DataFrame) -> pd.DataFrame: 30 | return products[(products['low_fats'] == 'Y') & (products['recyclable'] == 'Y')][['product_id']] 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use boolean indexing to filter rows where `low_fats == 'Y'` and `recyclable == 'Y'`. Return only the `product_id` column. 35 | - **Why Boolean Indexing?**: Pandas vectorized operations efficiently filter rows based on multiple conditions. 36 | - **Edge Cases**: 37 | - No qualifying products: Returns empty DataFrame. 38 | - Single product: Returns one row if it meets criteria. 39 | - Missing values: Handled by constraints (no nulls). 40 | - **Optimizations**: Use `&` for logical AND; select only `product_id` for minimal output. 41 | 42 | ## Performance Analysis 43 | - **Time Complexity**: O(n), where n is the number of rows in `products`, for vectorized filtering. 44 | - **Space Complexity**: O(k), where k is the number of rows in the output DataFrame. 45 | - **Pandas Efficiency**: Vectorized operations (`==`, `&`) are highly optimized. 46 | 47 | ## Best Practices 48 | - Use vectorized operations for filtering. 49 | - Select only required columns (`product_id`). 50 | - Use clear conditionals (`== 'Y'`). 51 | - Follow PEP 8 for Python code style. 52 | 53 | ## Alternative Approaches 54 | - **Query Method**: Use `products.query("low_fats == 'Y' and recyclable == 'Y'")[['product_id']]` (similar performance, less explicit). 55 | - **Loc Indexing**: Use `products.loc[(products['low_fats'] == 'Y') & (products['recyclable'] == 'Y'), ['product_id']]` (equivalent performance, more verbose). -------------------------------------------------------------------------------- /Python/Sorting_Searching/Easy/merge_sorted_array.md: -------------------------------------------------------------------------------- 1 | # Merge Sorted Array 2 | 3 | ## Problem Statement 4 | Given two sorted integer arrays `nums1` and `nums2`, merge `nums2` into `nums1` as one sorted array. `nums1` has enough space to hold additional elements from `nums2`. The number of elements initialized in `nums1` and `nums2` are `m` and `n` respectively. 5 | 6 | **Example**: 7 | - Input: `nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3` 8 | - Output: `[1,2,2,3,5,6]` 9 | 10 | **Constraints**: 11 | - `nums1.length == m + n` 12 | - `nums2.length == n` 13 | - `0 <= m, n <= 200` 14 | - `-10^9 <= nums1[i], nums2[i] <= 10^9` 15 | 16 | ## Solution 17 | 18 | ### Python 19 | ```python 20 | def merge(nums1: list[int], m: int, nums2: list[int], n: int) -> None: 21 | p1, p2, p = m - 1, n - 1, m + n - 1 22 | 23 | while p2 >= 0: 24 | if p1 >= 0 and nums1[p1] > nums2[p2]: 25 | nums1[p] = nums1[p1] 26 | p1 -= 1 27 | else: 28 | nums1[p] = nums2[p2] 29 | p2 -= 1 30 | p -= 1 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Merge from the end to avoid overwriting `nums1`. Use three pointers: `p1` for `nums1`, `p2` for `nums2`, and `p` for the merged array’s end. Compare `nums1[p1]` and `nums2[p2]`, placing the larger value at `p` and moving the corresponding pointer. 35 | - **Why Merge from End?**: Avoids shifting elements in `nums1`, as extra space is at the end. 36 | - **Edge Cases**: 37 | - `n=0`: `nums1` is already sorted. 38 | - `m=0`: Copy `nums2` into `nums1`. 39 | - Single element arrays: Compare and place directly. 40 | - **Optimizations**: In-place merging; single pass from end to start. 41 | 42 | ## Complexity Analysis 43 | - **Time Complexity**: O(m + n), as we process each element from both arrays once. 44 | - **Space Complexity**: O(1), as we merge in-place using only pointers. 45 | 46 | ## Best Practices 47 | - Use clear variable names (e.g., `p1`, `p2`). 48 | - For Python, use type hints for clarity. 49 | - For JavaScript, use concise conditionals. 50 | - For Java, follow Google Java Style Guide. 51 | - Merge from end to avoid extra space. 52 | 53 | ## Alternative Approaches 54 | - **Copy and Sort**: Copy `nums2` into `nums1` and sort (O((m+n) log (m+n)) time). Inefficient. 55 | - **Merge to New Array**: Merge into a new array, then copy back (O(m+n) time, O(m+n) space). Less space-efficient. -------------------------------------------------------------------------------- /JavaScript/Backtracking/Medium/subsets_ii.md: -------------------------------------------------------------------------------- 1 | # Subsets II 2 | 3 | ## Problem Statement 4 | Given an integer array `nums` that may contain duplicates, return all possible unique subsets (the power set). The solution set must not contain duplicate subsets. Return the answer in any order. 5 | 6 | **Example**: 7 | - Input: `nums = [1,2,2]` 8 | - Output: `[[],[1],[1,2],[1,2,2],[2],[2,2]]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 10` 12 | - `-10 <= nums[i] <= 10` 13 | 14 | ## Solution 15 | 16 | ### JavaScript 17 | ```javascript 18 | function subsetsWithDup(nums) { 19 | nums.sort((a, b) => a - b); 20 | const result = []; 21 | 22 | function backtrack(index, current) { 23 | result.push([...current]); 24 | for (let i = index; i < nums.length; i++) { 25 | if (i > index && nums[i] === nums[i - 1]) continue; 26 | current.push(nums[i]); 27 | backtrack(i + 1, current); 28 | current.pop(); 29 | } 30 | } 31 | 32 | backtrack(0, []); 33 | return result; 34 | } 35 | ``` 36 | 37 | ## Reasoning 38 | - **Approach**: Sort the array to group duplicates, then use backtracking to generate subsets. Skip duplicate elements at the same level to avoid duplicate subsets. Add each subset to the result. 39 | - **Why Sort?**: Sorting ensures duplicates are adjacent, making it easier to skip them. 40 | - **Edge Cases**: 41 | - Empty array: Return `[[]]`. 42 | - All duplicates: Generate unique subsets (e.g., `[1,1]` → `[[],[1],[1,1]]`). 43 | - **Optimizations**: Skip duplicates at the same recursion level; copy current list to avoid reference issues. 44 | 45 | ## Complexity Analysis 46 | - **Time Complexity**: O(2^n), where n is the length of `nums`, as there are up to 2^n subsets. Sorting takes O(n log n). 47 | - **Space Complexity**: O(n) for the recursion stack, plus O(2^n) for the output. 48 | 49 | ## Best Practices 50 | - Use clear variable names (e.g., `index`, `current`). 51 | - For Python, use type hints and sorting. 52 | - For JavaScript, use spread operator and sorting. 53 | - For Java, use `Arrays.sort` and follow Google Java Style Guide. 54 | - Skip duplicates to ensure unique subsets. 55 | 56 | ## Alternative Approaches 57 | - **Bit Manipulation**: Use binary numbers with duplicate handling (O(2^n) time). More complex. 58 | - **Iterative**: Build subsets iteratively (same complexity). Less intuitive. -------------------------------------------------------------------------------- /JavaScript/Sorting_Searching/Medium/top_k_frequent_elements.md: -------------------------------------------------------------------------------- 1 | # Top K Frequent Elements 2 | 3 | ## Problem Statement 4 | Given an integer array `nums` and an integer `k`, return the `k` most frequent elements. You may return the answer in any order. 5 | 6 | **Example**: 7 | - Input: `nums = [1,1,1,2,2,3], k = 2` 8 | - Output: `[1,2]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 10^5` 12 | - `-10^4 <= nums[i] <= 10^4` 13 | - `k` is in the range `[1, the number of unique elements in the array]`. 14 | 15 | ## Solution 16 | 17 | ### JavaScript 18 | ```javascript 19 | function topKFrequent(nums, k) { 20 | const count = new Map(); 21 | for (const num of nums) { 22 | count.set(num, (count.get(num) || 0) + 1); 23 | } 24 | 25 | const heap = new MinPriorityQueue({ priority: x => x[0] }); 26 | for (const [num, freq] of count) { 27 | heap.enqueue([freq, num]); 28 | if (heap.size() > k) heap.dequeue(); 29 | } 30 | 31 | return heap.toArray().map(x => x.element[1]); 32 | } 33 | ``` 34 | 35 | ## Reasoning 36 | - **Approach**: Count frequencies using a hash map. Use a min-heap of size k to store elements by frequency. For each unique element, add to the heap and remove the smallest frequency if size exceeds k. Return the remaining elements. 37 | - **Why Min-Heap?**: Efficiently maintains k most frequent elements with O(log k) operations. 38 | - **Edge Cases**: 39 | - k=1: Return most frequent element. 40 | - Single unique element: Return it if k=1. 41 | - k equals unique elements: Return all. 42 | - **Optimizations**: Use min-heap to limit size to k; avoid sorting frequencies. 43 | 44 | ## Complexity Analysis 45 | - **Time Complexity**: O(n log k), where n is the length of `nums`. Counting is O(n), heap operations are O(log k) per unique element. 46 | - **Space Complexity**: O(n) for the hash map, O(k) for the heap. 47 | 48 | ## Best Practices 49 | - Use clear variable names (e.g., `count`, `heap`). 50 | - For Python, use `Counter` and `heapq`. 51 | - For JavaScript, use `Map` and priority queue library. 52 | - For Java, use `HashMap` and `PriorityQueue`, follow Google Java Style Guide. 53 | - Process frequencies efficiently with heap. 54 | 55 | ## Alternative Approaches 56 | - **Sorting**: Sort by frequency (O(n log n) time). Less efficient. 57 | - **Bucket Sort**: Use frequency buckets (O(n) time, O(n) space). Faster but more complex. -------------------------------------------------------------------------------- /Numpy/Easy/array_reshape.md: -------------------------------------------------------------------------------- 1 | # Array Reshape 2 | 3 | ## Problem Statement 4 | Write a NumPy program to reshape a 1D array into a 2D array with specified rows and columns. 5 | 6 | **Input**: 7 | - `arr`: 1D array of numbers (e.g., `[1, 2, 3, 4, 5, 6]`) 8 | - `rows`: Number of rows (e.g., `2`) 9 | - `cols`: Number of columns (e.g., `3`) 10 | 11 | **Output**: 12 | - 2D array of shape `(rows, cols)` (e.g., `[[1, 2, 3], [4, 5, 6]]`) 13 | 14 | **Constraints**: 15 | - `1 <= len(arr) <= 10^5` 16 | - `rows * cols = len(arr)` 17 | - `1 <= rows, cols <= 10^3` 18 | - `-10^5 <= arr[i] <= 10^5` 19 | 20 | ## Solution 21 | ```python 22 | import numpy as np 23 | 24 | def array_reshape(arr: list, rows: int, cols: int) -> np.ndarray: 25 | # Convert to numpy array and reshape 26 | return np.array(arr).reshape(rows, cols) 27 | ``` 28 | 29 | ## Reasoning 30 | - **Approach**: Convert input list to NumPy array. Use `reshape` to transform into a 2D array with `rows` and `cols`. Return the result. 31 | - **Why np.reshape?**: Efficiently reorganizes array without copying data. 32 | - **Edge Cases**: 33 | - Invalid shape: Ensured by `rows * cols = len(arr)`. 34 | - Single element: Reshapes to `(1, 1)` if valid. 35 | - Large arrays: NumPy handles efficiently. 36 | - **Optimizations**: `np.reshape` is a view operation, minimizing memory usage. 37 | 38 | ## Performance Analysis 39 | - **Time Complexity**: O(1), as reshaping is a metadata operation. 40 | - **Space Complexity**: O(n), where n is the array length, for the input array. 41 | - **NumPy Efficiency**: `reshape` is highly optimized, avoiding data copying. 42 | 43 | ## Best Practices 44 | - Use `np.reshape` for efficient array reshaping. 45 | - Validate `rows * cols = len(arr)` before reshaping. 46 | - Follow PEP 8 for Python code style. 47 | 48 | ## Alternative Approaches 49 | - **Manual Reshape**: Use loops (O(n), inefficient). 50 | ```python 51 | def array_reshape(arr: list, rows: int, cols: int) -> list: 52 | result = [] 53 | for i in range(rows): 54 | result.append(arr[i * cols:(i + 1) * cols]) 55 | return result 56 | ``` 57 | - **np.array_split**: Split and stack (O(n), less direct). 58 | ```python 59 | import numpy as np 60 | def array_reshape(arr: list, rows: int, cols: int) -> np.ndarray: 61 | arr = np.array(arr) 62 | return np.array([arr[i * cols:(i + 1) * cols] for i in range(rows)]) 63 | ``` -------------------------------------------------------------------------------- /Java/Sorting_Searching/Easy/valid_anagram.md: -------------------------------------------------------------------------------- 1 | # Valid Anagram 2 | 3 | ## Problem Statement 4 | Given two strings `s` and `t`, return `true` if `t` is an anagram of `s`, and `false` otherwise. An anagram is a word formed by rearranging the letters of another. 5 | 6 | **Example**: 7 | - Input: `s = "anagram", t = "nagaram"` 8 | - Output: `true` 9 | 10 | **Constraints**: 11 | - `1 <= s.length, t.length <= 5 * 10^4` 12 | - `s` and `t` consist of lowercase English letters. 13 | 14 | ## Solution 15 | 16 | ### Java 17 | ```java 18 | class Solution { 19 | public boolean isAnagram(String s, String t) { 20 | if (s.length() != t.length()) return false; 21 | 22 | int[] count = new int[26]; 23 | for (int i = 0; i < s.length(); i++) { 24 | count[s.charAt(i) - 'a']++; 25 | count[t.charAt(i) - 'a']--; 26 | } 27 | 28 | for (int x : count) { 29 | if (x != 0) return false; 30 | } 31 | return true; 32 | } 33 | } 34 | ``` 35 | 36 | ## Reasoning 37 | - **Approach**: Use a frequency array to count character occurrences in `s` and `t`. Increment for `s` characters, decrement for `t` characters. If all counts are zero, the strings are anagrams. Check lengths first to avoid unnecessary processing. 38 | - **Why Frequency Array?**: Efficiently tracks character counts in O(n) time with constant space for lowercase letters. 39 | - **Edge Cases**: 40 | - Different lengths: Return false. 41 | - Empty strings: Return true (if both empty). 42 | - Same characters, different counts: Return false. 43 | - **Optimizations**: Single pass over strings; use fixed-size array for 26 letters. 44 | 45 | ## Complexity Analysis 46 | - **Time Complexity**: O(n), where n is the length of `s` or `t`, as we process each character once. 47 | - **Space Complexity**: O(1), as the frequency array is fixed at 26 elements. 48 | 49 | ## Best Practices 50 | - Use clear variable names (e.g., `count`). 51 | - For Python, use type hints and `zip` for iteration. 52 | - For JavaScript, use `charCodeAt` for character indexing. 53 | - For Java, follow Google Java Style Guide. 54 | - Check length early to optimize. 55 | 56 | ## Alternative Approaches 57 | - **Sorting**: Sort both strings and compare (O(n log n) time). Less efficient. 58 | - **Hash Map**: Use a map to count characters (O(n) time, O(n) space). Less space-efficient for fixed alphabet. -------------------------------------------------------------------------------- /Python/Backtracking/Medium/permutations.md: -------------------------------------------------------------------------------- 1 | # Permutations 2 | 3 | ## Problem Statement 4 | Given an array `nums` of distinct integers, return all possible permutations. You can return the answer in any order. 5 | 6 | **Example**: 7 | - Input: `nums = [1,2,3]` 8 | - Output: `[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 6` 12 | - `-10 <= nums[i] <= 10` 13 | - All integers in `nums` are unique. 14 | 15 | ## Solution 16 | 17 | ### Python 18 | ```python 19 | def permute(nums: list[int]) -> list[list[int]]: 20 | result = [] 21 | 22 | def backtrack(current: list[int], remaining: list[int]) -> None: 23 | if not remaining: 24 | result.append(current[:]) 25 | return 26 | for i in range(len(remaining)): 27 | backtrack(current + [remaining[i]], remaining[:i] + remaining[i+1:]) 28 | 29 | backtrack([], nums) 30 | return result 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use backtracking to generate all permutations by selecting each number from the remaining set and recursing. Track used numbers to avoid duplicates. Add the current permutation to the result when all numbers are used. 35 | - **Why Backtracking?**: It systematically explores all possible arrangements, ensuring all permutations are generated. 36 | - **Edge Cases**: 37 | - Single element: Returns one permutation. 38 | - Empty array: Returns empty list of lists. 39 | - **Optimizations**: In Java, use a contains check to avoid extra array copying; in Python/JavaScript, slice arrays to create new remaining sets. 40 | 41 | ## Complexity Analysis 42 | - **Time Complexity**: O(n!), where n is the length of `nums`, as there are n! permutations. 43 | - **Space Complexity**: O(n) for the recursion stack and current permutation, plus O(n!) for the output. 44 | 45 | ## Best Practices 46 | - Use clear variable names (e.g., `current`, `remaining`). 47 | - For Python, use type hints and list slicing. 48 | - For JavaScript, use spread operator for array copying. 49 | - For Java, use `ArrayList` and follow Google Java Style Guide. 50 | - Avoid duplicate permutations by tracking used elements. 51 | 52 | ## Alternative Approaches 53 | - **Iterative**: Generate permutations using factorial number system (O(n!) time). More complex. 54 | - **Heap’s Algorithm**: Non-recursive permutation generation (O(n!) time). Less intuitive. -------------------------------------------------------------------------------- /Python/Stacks_Queues/Hard/sliding_window_maximum.md: -------------------------------------------------------------------------------- 1 | # Sliding Window Maximum 2 | 3 | ## Problem Statement 4 | Given an array `nums` and an integer `k`, return the maximum element in each sliding window of size `k` as it slides from left to right. 5 | 6 | **Example**: 7 | - Input: `nums = [1,3,-1,-3,5,3,6,7], k = 3` 8 | - Output: `[3,3,5,5,6,7]` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 10^5` 12 | - `-10^4 <= nums[i] <= 10^4` 13 | - `1 <= k <= nums.length` 14 | 15 | ## Solution 16 | 17 | ### Python 18 | ```python 19 | from collections import deque 20 | 21 | def maxSlidingWindow(nums: list[int], k: int) -> list[int]: 22 | result = [] 23 | dq = deque() 24 | 25 | for i in range(len(nums)): 26 | while dq and dq[0] <= i - k: 27 | dq.popleft() 28 | while dq and nums[dq[-1]] <= nums[i]: 29 | dq.pop() 30 | dq.append(i) 31 | if i >= k - 1: 32 | result.append(nums[dq[0]]) 33 | 34 | return result 35 | ``` 36 | 37 | ## Reasoning 38 | - **Approach**: Use a deque to maintain indices of potential maximums in a decreasing order. For each index, remove out-of-window indices from the front and smaller elements from the back. Add the current index and store the front element as the maximum when the window is full. 39 | - **Why Deque?**: Allows O(1) access to both ends, maintaining a monotonic queue of indices for efficient maximum tracking. 40 | - **Edge Cases**: 41 | - k=1: Return original array. 42 | - Single window: Return maximum of first k elements. 43 | - All same values: Return array of that value. 44 | - **Optimizations**: Use deque for O(1) operations; single pass through array. 45 | 46 | ## Complexity Analysis 47 | - **Time Complexity**: O(n), where n is the length of `nums`, as each index is pushed and popped at most once. 48 | - **Space Complexity**: O(k), for the deque, plus O(n-k+1) for the output array. 49 | 50 | ## Best Practices 51 | - Use clear variable names (e.g., `dq`, `result`). 52 | - For Python, use `deque` and type hints. 53 | - For JavaScript, use array as deque with `shift`/`pop`. 54 | - For Java, use `Deque` and follow Google Java Style Guide. 55 | - Maintain monotonic property for efficiency. 56 | 57 | ## Alternative Approaches 58 | - **Brute Force**: Find max for each window (O(n*k) time). Too slow. 59 | - **Priority Queue**: Use max heap for windows (O(n log k) time). Less efficient. -------------------------------------------------------------------------------- /Java/Arrays/Hard/first_missing_positive.md: -------------------------------------------------------------------------------- 1 | # First Missing Positive 2 | 3 | ## Problem Statement 4 | Given an unsorted integer array `nums`, return the smallest missing positive integer. You must implement an algorithm that runs in O(n) time and uses O(1) space. 5 | 6 | **Example**: 7 | - Input: `nums = [1,2,0]` 8 | - Output: `3` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 5 * 10^5` 12 | - `-2^31 <= nums[i] <= 2^31 - 1` 13 | 14 | ## Solution 15 | 16 | ### Java 17 | ```java 18 | class Solution { 19 | public int firstMissingPositive(int[] nums) { 20 | int n = nums.length; 21 | for (int i = 0; i < n; i++) { 22 | if (nums[i] <= 0 || nums[i] > n) { 23 | nums[i] = n + 1; 24 | } 25 | } 26 | for (int i = 0; i < n; i++) { 27 | int num = Math.abs(nums[i]); 28 | if (num <= n) { 29 | nums[num - 1] = -Math.abs(nums[num - 1]); 30 | } 31 | } 32 | for (int i = 0; i < n; i++) { 33 | if (nums[i] > 0) { 34 | return i + 1; 35 | } 36 | } 37 | return n + 1; 38 | } 39 | } 40 | ``` 41 | 42 | ## Reasoning 43 | - **Approach**: Use the array itself as a hash table. Ignore non-positive and numbers > n. Place each number `x` at index `x-1` by marking the index negative. The first positive index indicates the missing number. 44 | - **Why In-Place Marking?**: Achieves O(1) space by using the array to track presence of numbers 1 to n. 45 | - **Edge Cases**: 46 | - Empty array: Return 1. 47 | - All numbers present: Return n + 1. 48 | - Negative numbers: Ignored via preprocessing. 49 | - **Optimizations**: Three linear passes; no extra space. 50 | 51 | ## Complexity Analysis 52 | - **Time Complexity**: O(n), where n is the length of `nums`. Three passes through the array. 53 | - **Space Complexity**: O(1), using the array itself. 54 | 55 | ## Best Practices 56 | - Use clear variable names (e.g., `num`, `n`). 57 | - For Python, use type hints and handle edge cases. 58 | - For JavaScript, use `Math.abs` for clarity. 59 | - For Java, follow Google Java Style Guide. 60 | - Use array indices to avoid extra space. 61 | 62 | ## Alternative Approaches 63 | - **Hash Set**: Store numbers and check for missing (O(n) time, O(n) space). Violates space constraint. 64 | - **Sorting**: Sort and find missing number (O(n log n) time). Too slow. -------------------------------------------------------------------------------- /JavaScript/Sorting_Searching/Easy/merge_sorted_array.md: -------------------------------------------------------------------------------- 1 | # Merge Sorted Array 2 | 3 | ## Problem Statement 4 | Given two sorted integer arrays `nums1` and `nums2`, merge `nums2` into `nums1` as one sorted array. `nums1` has enough space to hold additional elements from `nums2`. The number of elements initialized in `nums1` and `nums2` are `m` and `n` respectively. 5 | 6 | **Example**: 7 | - Input: `nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3` 8 | - Output: `[1,2,2,3,5,6]` 9 | 10 | **Constraints**: 11 | - `nums1.length == m + n` 12 | - `nums2.length == n` 13 | - `0 <= m, n <= 200` 14 | - `-10^9 <= nums1[i], nums2[i] <= 10^9` 15 | 16 | ## Solution 17 | 18 | ### JavaScript 19 | ```javascript 20 | function merge(nums1, m, nums2, n) { 21 | let p1 = m - 1, p2 = n - 1, p = m + n - 1; 22 | 23 | while (p2 >= 0) { 24 | if (p1 >= 0 && nums1[p1] > nums2[p2]) { 25 | nums1[p] = nums1[p1]; 26 | p1--; 27 | } else { 28 | nums1[p] = nums2[p2]; 29 | p2--; 30 | } 31 | p--; 32 | } 33 | } 34 | ``` 35 | 36 | ## Reasoning 37 | - **Approach**: Merge from the end to avoid overwriting `nums1`. Use three pointers: `p1` for `nums1`, `p2` for `nums2`, and `p` for the merged array’s end. Compare `nums1[p1]` and `nums2[p2]`, placing the larger value at `p` and moving the corresponding pointer. 38 | - **Why Merge from End?**: Avoids shifting elements in `nums1`, as extra space is at the end. 39 | - **Edge Cases**: 40 | - `n=0`: `nums1` is already sorted. 41 | - `m=0`: Copy `nums2` into `nums1`. 42 | - Single element arrays: Compare and place directly. 43 | - **Optimizations**: In-place merging; single pass from end to start. 44 | 45 | ## Complexity Analysis 46 | - **Time Complexity**: O(m + n), as we process each element from both arrays once. 47 | - **Space Complexity**: O(1), as we merge in-place using only pointers. 48 | 49 | ## Best Practices 50 | - Use clear variable names (e.g., `p1`, `p2`). 51 | - For Python, use type hints for clarity. 52 | - For JavaScript, use concise conditionals. 53 | - For Java, follow Google Java Style Guide. 54 | - Merge from end to avoid extra space. 55 | 56 | ## Alternative Approaches 57 | - **Copy and Sort**: Copy `nums2` into `nums1` and sort (O((m+n) log (m+n)) time). Inefficient. 58 | - **Merge to New Array**: Merge into a new array, then copy back (O(m+n) time, O(m+n) space). Less space-efficient. -------------------------------------------------------------------------------- /Python/Linked_Lists/Easy/linked_list_cycle.md: -------------------------------------------------------------------------------- 1 | # Linked List Cycle 2 | 3 | ## Problem Statement 4 | Given the head of a linked list, determine if the list has a cycle. A cycle exists if a node can be reached again by following the next pointers. 5 | 6 | **Example**: 7 | - Input: `head = [3,2,0,-4], pos = 1` (node at index 1 is connected to by the last node) 8 | - Output: `true` 9 | 10 | **Constraints**: 11 | - The number of nodes in the list is in the range `[0, 10^4]`. 12 | - `-10^5 <= Node.val <= 10^5` 13 | - `pos` is -1 or a valid index in the linked list. 14 | 15 | ## Solution 16 | 17 | ### Python 18 | ```python 19 | class ListNode: 20 | def __init__(self, val=0, next=None): 21 | self.val = val 22 | self.next = next 23 | 24 | def hasCycle(head: ListNode) -> bool: 25 | if not head or not head.next: 26 | return False 27 | slow = head 28 | fast = head.next 29 | 30 | while slow != fast: 31 | if not fast or not fast.next: 32 | return False 33 | slow = slow.next 34 | fast = fast.next.next 35 | 36 | return True 37 | ``` 38 | 39 | ## Reasoning 40 | - **Approach**: Use Floyd’s Cycle-Finding Algorithm (two-pointer technique). Move a slow pointer one step and a fast pointer two steps. If they meet, a cycle exists. If fast reaches the end, no cycle exists. 41 | - **Why Floyd’s Algorithm?**: Detects cycles in O(n) time with O(1) space, leveraging the fact that fast will catch up to slow in a cycle. 42 | - **Edge Cases**: 43 | - Empty list or single node: No cycle. 44 | - Cycle at head: Detected by meeting pointers. 45 | - **Optimizations**: Start fast at `head.next` to avoid initial overlap; check null pointers. 46 | 47 | ## Complexity Analysis 48 | - **Time Complexity**: O(n), where n is the number of nodes, as fast pointer catches up in linear time or reaches the end. 49 | - **Space Complexity**: O(1), as only two pointers are used. 50 | 51 | ## Best Practices 52 | - Use clear variable names (e.g., `slow`, `fast`). 53 | - For Python, use type hints for clarity. 54 | - For JavaScript, use early null checks. 55 | - For Java, follow Google Java Style Guide. 56 | - Optimize by starting fast at `head.next`. 57 | 58 | ## Alternative Approaches 59 | - **Hash Set**: Store visited nodes in a set (O(n) time, O(n) space). Less space-efficient. 60 | - **Marking Nodes**: Modify node values to mark visits (O(n) time, O(1) space, but destructive). -------------------------------------------------------------------------------- /Python/Stacks_Queues/Easy/valid_parentheses.md: -------------------------------------------------------------------------------- 1 | # Valid Parentheses 2 | 3 | ## Problem Statement 4 | Given a string `s` containing only the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid. A string is valid if: 5 | 1. Open brackets must be closed by the same type of brackets. 6 | 2. Open brackets must be closed in the correct order. 7 | 8 | **Example**: 9 | - Input: `s = "()[]{}"` 10 | - Output: `true` 11 | 12 | **Constraints**: 13 | - `1 <= s.length <= 10^4` 14 | - `s` consists of parentheses only '()[]{}'. 15 | 16 | ## Solution 17 | 18 | ### Python 19 | ```python 20 | def isValid(s: str) -> bool: 21 | stack = [] 22 | brackets = {')': '(', '}': '{', ']': '['} 23 | 24 | for c in s: 25 | if c in brackets.values(): 26 | stack.append(c) 27 | elif c in brackets: 28 | if not stack or stack.pop() != brackets[c]: 29 | return False 30 | 31 | return len(stack) == 0 32 | ``` 33 | 34 | ## Reasoning 35 | - **Approach**: Use a stack to track opening brackets. For each character, if it’s an opening bracket, push it onto the stack. If it’s a closing bracket, check if the stack’s top matches the corresponding opening bracket. If not, or stack is empty, return false. Finally, check if the stack is empty. 36 | - **Why Stack?**: Ensures correct order of bracket matching by tracking opening brackets until their closing counterparts are found. 37 | - **Edge Cases**: 38 | - Single character: Return false. 39 | - Unmatched brackets: Return false. 40 | - Empty string: Return true. 41 | - **Optimizations**: Use a hash map for bracket pairs; single pass through the string. 42 | 43 | ## Complexity Analysis 44 | - **Time Complexity**: O(n), where n is the length of `s`, as we process each character once. 45 | - **Space Complexity**: O(n), for the stack in the worst case (all opening brackets). 46 | 47 | ## Best Practices 48 | - Use clear variable names (e.g., `stack`, `brackets`). 49 | - For Python, use type hints and dictionary for mapping. 50 | - For JavaScript, use object for bracket pairs and concise checks. 51 | - For Java, use `Deque` and follow Google Java Style Guide. 52 | - Check stack emptiness for validity. 53 | 54 | ## Alternative Approaches 55 | - **Recursive**: Parse string recursively (O(n) time, O(n) space). More complex. 56 | - **Counter-Based**: Count bracket pairs (O(n) time, O(1) space). Fails for order validation. -------------------------------------------------------------------------------- /JavaScript/Sorting_Searching/Hard/find_minimum_in_rotated_sorted_array_ii.markdown: -------------------------------------------------------------------------------- 1 | # Find Minimum in Rotated Sorted Array II 2 | 3 | ## Problem Statement 4 | Given a sorted array `nums` rotated at some pivot, with possible duplicates, find the minimum element. The algorithm must run in O(log n) time in the average case. 5 | 6 | **Example**: 7 | - Input: `nums = [2,2,2,0,1]` 8 | - Output: `0` 9 | 10 | **Constraints**: 11 | - `1 <= nums.length <= 5000` 12 | - `-5000 <= nums[i] <= 5000` 13 | - `nums` is sorted and rotated, with possible duplicates. 14 | 15 | ## Solution 16 | 17 | ### JavaScript 18 | ```javascript 19 | function findMin(nums) { 20 | let left = 0, right = nums.length - 1; 21 | 22 | while (left < right) { 23 | const mid = Math.floor((left + right) / 2); 24 | if (nums[mid] > nums[right]) { 25 | left = mid + 1; 26 | } else if (nums[mid] < nums[right]) { 27 | right = mid; 28 | } else { 29 | right--; 30 | } 31 | } 32 | 33 | return nums[left]; 34 | } 35 | ``` 36 | 37 | ## Reasoning 38 | - **Approach**: Use binary search, comparing `nums[mid]` with `nums[right]`. If greater, minimum is in right half; if less, minimum is in left half including mid; if equal, exclude rightmost element due to duplicates. Converge to the minimum. 39 | - **Why Binary Search?**: Handles rotation and duplicates, aiming for O(log n) average time, though worst case is O(n) with many duplicates. 40 | - **Edge Cases**: 41 | - Single element: Return it. 42 | - All duplicates: Linear scan in worst case. 43 | - No rotation: Minimum at index 0. 44 | - **Optimizations**: Use `right--` to handle duplicates; avoid overflow with midpoint calculation. 45 | 46 | ## Complexity Analysis 47 | - **Time Complexity**: O(log n) average, O(n) worst case (all duplicates). 48 | - **Space Complexity**: O(1), as only a few variables are used. 49 | 50 | ## Best Practices 51 | - Use clear variable names (e.g., `left`, `right`). 52 | - For Python, use type hints. 53 | - For JavaScript, use `Math.floor` for integer division. 54 | - For Java, follow Google Java Style Guide and use overflow-safe midpoint. 55 | - Handle duplicates by excluding rightmost element. 56 | 57 | ## Alternative Approaches 58 | - **Linear Scan**: Find minimum by iteration (O(n) time). Too slow. 59 | - **Find Pivot**: Locate rotation point, then take next element (O(log n) average). Similar complexity. -------------------------------------------------------------------------------- /Python/Backtracking/Easy/generate_parentheses.md: -------------------------------------------------------------------------------- 1 | # Generate Parentheses 2 | 3 | ## Problem Statement 4 | Given an integer `n`, generate all valid combinations of `n` pairs of parentheses. A combination is valid if it is well-formed (every open parenthesis has a matching close parenthesis). 5 | 6 | **Example**: 7 | - Input: `n = 3` 8 | - Output: `["((()))","(()())","(())()","()(())","()()()"]` 9 | 10 | **Constraints**: 11 | - `1 <= n <= 8` 12 | 13 | ## Solution 14 | 15 | ### Python 16 | ```python 17 | def generateParenthesis(n: int) -> list[str]: 18 | result = [] 19 | 20 | def backtrack(open_count: int, close_count: int, current: str) -> None: 21 | if len(current) == 2 * n: 22 | result.append(current) 23 | return 24 | if open_count < n: 25 | backtrack(open_count + 1, close_count, current + "(") 26 | if close_count < open_count: 27 | backtrack(open_count, close_count + 1, current + ")") 28 | 29 | backtrack(0, 0, "") 30 | return result 31 | ``` 32 | 33 | ## Reasoning 34 | - **Approach**: Use backtracking to build valid parentheses combinations. Track open and close parenthesis counts. Add an open parenthesis if fewer than `n` are used, and a close parenthesis if there are more open than close. Add to result when length is `2n`. 35 | - **Why Backtracking?**: Ensures only valid combinations by enforcing parentheses rules during recursion. 36 | - **Edge Cases**: 37 | - `n = 1`: Returns `["()"]`. 38 | - Invalid sequences: Prevented by count checks. 39 | - **Optimizations**: Prune invalid branches early by checking counts. 40 | 41 | ## Complexity Analysis 42 | - **Time Complexity**: O(4^n / √n), the nth Catalan number, representing the number of valid parentheses combinations. 43 | - **Space Complexity**: O(n) for the recursion stack, plus O(4^n / √n) for the output. 44 | 45 | ## Best Practices 46 | - Use clear variable names (e.g., `open_count`, `close_count`). 47 | - For Python, use type hints for clarity. 48 | - For JavaScript, use modern function syntax. 49 | - For Java, use `ArrayList` and follow Google Java Style Guide. 50 | - Validate parentheses counts to avoid invalid combinations. 51 | 52 | ## Alternative Approaches 53 | - **Dynamic Programming**: Build solutions iteratively (O(4^n / √n) time, O(n) space). More complex. 54 | - **Closure Number**: Use mathematical properties of Catalan numbers (same complexity). Less intuitive. -------------------------------------------------------------------------------- /JavaScript/Dynamic_Programming/Hard/longest_valid_parentheses.md: -------------------------------------------------------------------------------- 1 | # Longest Valid Parentheses 2 | 3 | ## Problem Statement 4 | Given a string containing only '(' and ')', return the length of the longest valid (well-formed) parentheses substring. 5 | 6 | **Example**: 7 | - Input: `s = "(()"` 8 | - Output: `2` 9 | - Explanation: The longest valid substring is "()". 10 | 11 | **Constraints**: 12 | - `0 <= s.length <= 3 * 10^4` 13 | - `s[i]` is '(' or ')'. 14 | 15 | ## Solution 16 | 17 | ### JavaScript 18 | ```javascript 19 | function longestValidParentheses(s) { 20 | const n = s.length; 21 | const dp = new Array(n + 1).fill(0); 22 | let maxLength = 0; 23 | for (let i = 2; i <= n; i++) { 24 | if (s[i - 1] === ')') { 25 | if (s[i - 2] === '(') { 26 | dp[i] = dp[i - 2] + 2; 27 | } else if (i - dp[i - 1] - 2 >= 0 && s[i - dp[i - 1] - 2] === '(') { 28 | dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2; 29 | } 30 | maxLength = Math.max(maxLength, dp[i]); 31 | } 32 | } 33 | return maxLength; 34 | } 35 | ``` 36 | 37 | ## Reasoning 38 | - **Approach**: Use a 1D DP array where `dp[i]` represents the length of the longest valid parentheses substring ending at index `i-1`. For a ')', check if the previous character is '(' (forming "()" pair) or if there's a valid pair before the previous valid substring. Update `dp[i]` accordingly and track the maximum length. 39 | - **Why DP?**: Efficiently computes valid substring lengths by leveraging previous results. 40 | - **Edge Cases**: 41 | - Empty string: Return 0. 42 | - No valid pairs: Return 0. 43 | - **Optimizations**: Use 1D array; avoid stack-based solutions for simplicity. 44 | 45 | ## Complexity Analysis 46 | - **Time Complexity**: O(n), single pass through the string. 47 | - **Space Complexity**: O(n) for the DP array. 48 | 49 | ## Best Practices 50 | - Use clear variable names (e.g., `dp`, `max_length`). 51 | - For Python, use type hints and array initialization. 52 | - For JavaScript, use array methods for clarity. 53 | - For Java, follow Google Java Style Guide. 54 | - Handle closing parentheses cases carefully. 55 | 56 | ## Alternative Approaches 57 | - **Stack**: Use a stack to track indices of '(' and compute lengths (O(n) time, O(n) space). More complex. 58 | - **Two-Pass Counting**: Count open/close parentheses in both directions (O(n) time, O(1) space). Less intuitive. -------------------------------------------------------------------------------- /Python/Stacks_Queues/Medium/daily_temperatures.md: -------------------------------------------------------------------------------- 1 | # Daily Temperatures 2 | 3 | ## Problem Statement 4 | Given an array of integers `temperatures` representing daily temperatures, return an array `answer` such that `answer[i]` is the number of days until a warmer day (i.e., the first day with a higher temperature). If no such day exists, set `answer[i] = 0`. 5 | 6 | **Example**: 7 | - Input: `temperatures = [73,74,75,71,69,72,76,73]` 8 | - Output: `[1,1,4,2,1,1,0,0]` 9 | 10 | **Constraints**: 11 | - `1 <= temperatures.length <= 10^5` 12 | - `30 <= temperatures[i] <= 100` 13 | 14 | ## Solution 15 | 16 | ### Python 17 | ```python 18 | def dailyTemperatures(temperatures: list[int]) -> list[int]: 19 | n = len(temperatures) 20 | answer = [0] * n 21 | stack = [] 22 | 23 | for i in range(n): 24 | while stack and temperatures[i] > temperatures[stack[-1]]: 25 | prev_index = stack.pop() 26 | answer[prev_index] = i - prev_index 27 | stack.append(i) 28 | 29 | return answer 30 | ``` 31 | 32 | ## Reasoning 33 | - **Approach**: Use a monotonic stack to track indices of temperatures in decreasing order. For each temperature, pop indices from the stack where the temperature is lower, calculating the day difference. Push the current index onto the stack. 34 | - **Why Monotonic Stack?**: Efficiently finds the next warmer day in one pass by maintaining a stack of indices with decreasing temperatures. 35 | - **Edge Cases**: 36 | - Single day: Return [0]. 37 | - No warmer day: Answer remains 0 (default). 38 | - All same temperature: All answers are 0. 39 | - **Optimizations**: Single pass; use stack to avoid redundant comparisons. 40 | 41 | ## Complexity Analysis 42 | - **Time Complexity**: O(n), where n is the length of `temperatures`, as each index is pushed and popped at most once. 43 | - **Space Complexity**: O(n), for the stack and output array. 44 | 45 | ## Best Practices 46 | - Use clear variable names (e.g., `stack`, `prevIndex`). 47 | - For Python, use type hints and list as stack. 48 | - For JavaScript, use array as stack with `push`/`pop`. 49 | - For Java, use `Deque` and follow Google Java Style Guide. 50 | - Initialize output array with zeros for simplicity. 51 | 52 | ## Alternative Approaches 53 | - **Brute Force**: For each day, scan forward for a warmer day (O(n^2) time). Too slow. 54 | - **Array Scan**: Store indices and scan right (O(n^2) worst case). Inefficient. -------------------------------------------------------------------------------- /Java/Arrays/Easy/majority_element.md: -------------------------------------------------------------------------------- 1 | # Majority Element 2 | 3 | ## Problem Statement 4 | Given an array `nums` of size `n`, return the majority element. The majority element is the element that appears more than `⌊n/2⌋` times. You may assume the majority element always exists. 5 | 6 | **Example**: 7 | - Input: `nums = [2,2,1,1,1,2,2]` 8 | - Output: `2` 9 | - Explanation: `2` appears 4 times, which is more than `n/2 = 3.5`. 10 | 11 | **Constraints**: 12 | - `1 <= nums.length <= 5 * 10^4` 13 | - `-10^9 <= nums[i] <= 10^9` 14 | 15 | ## Solution 16 | 17 | ### Java 18 | ```java 19 | class Solution { 20 | public int majorityElement(int[] nums) { 21 | int count = 0; 22 | int candidate = 0; 23 | for (int num : nums) { 24 | if (count == 0) { 25 | candidate = num; 26 | } 27 | count += (num == candidate) ? 1 : -1; 28 | } 29 | return candidate; 30 | } 31 | } 32 | ``` 33 | 34 | ## Reasoning 35 | - **Approach**: Use Boyer-Moore Voting Algorithm. Since the majority element appears more than `n/2` times, maintain a candidate and count. Increment count when seeing the candidate, decrement otherwise. When count reaches 0, pick a new candidate. The final candidate is the majority element. 36 | - **Why Boyer-Moore?**: It guarantees the majority element in a single pass without extra space, leveraging the fact that the majority element outweighs others. 37 | - **Edge Cases**: 38 | - Single element: Returns that element. 39 | - Majority element exists: Guaranteed by problem constraints. 40 | - **Optimizations**: Single pass with minimal variables; no need for validation due to problem assumptions. 41 | 42 | ## Complexity Analysis 43 | - **Time Complexity**: O(n), where n is the length of `nums`. Single pass through the array. 44 | - **Space Complexity**: O(1), as only two variables are used. 45 | 46 | ## Best Practices 47 | - Use clear variable names (e.g., `candidate`, `count`). 48 | - For Python, include type hints for clarity. 49 | - For JavaScript, use `for...of` for readability. 50 | - For Java, follow Google Java Style Guide. 51 | - Keep logic simple to leverage the algorithm’s elegance. 52 | 53 | ## Alternative Approaches 54 | - **Hash Map**: Count frequencies and return the element with count > `n/2` (O(n) time, O(n) space). 55 | - **Sorting**: Sort the array and return the middle element (O(n log n) time, O(1) space). Less efficient than Boyer-Moore. --------------------------------------------------------------------------------