diff --git a/.husky/pre-commit b/.husky/pre-commit index 6cd3f7d..086aeb8 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1,2 @@ npm run format:json +npm run format:python diff --git a/data/leetcode-problems.json b/data/leetcode-problems.json index d3382e2..4db06ab 100644 --- a/data/leetcode-problems.json +++ b/data/leetcode-problems.json @@ -26444,5 +26444,40 @@ "title": "Minimum Distance Excluding One Maximum Weighted Edge", "difficulty": "Medium", "link": "https://leetcode.com/problems/minimum-distance-excluding-one-maximum-weighted-edge/" + }, + "3779": { + "id": 3779, + "category": "Array & Hashing", + "title": "Minimum Number of Operations to Have Distinct Elements", + "difficulty": "Medium", + "link": "https://leetcode.com/problems/minimum-number-of-operations-to-have-distinct-elements/" + }, + "3780": { + "id": 3780, + "category": "Array & Hashing", + "title": "Maximum Sum of Three Numbers Divisible by Three", + "difficulty": "Medium", + "link": "https://leetcode.com/problems/maximum-sum-of-three-numbers-divisible-by-three/" + }, + "3781": { + "id": 3781, + "category": "Greedy", + "title": "Maximum Score After Binary Swaps", + "difficulty": "Medium", + "link": "https://leetcode.com/problems/maximum-score-after-binary-swaps/" + }, + "3783": { + "id": 3783, + "category": "Math & Geometry", + "title": "Mirror Distance of an Integer", + "difficulty": "Easy", + "link": "https://leetcode.com/problems/mirror-distance-of-an-integer/" + }, + "3784": { + "id": 3784, + "category": "Greedy", + "title": "Minimum Deletion Cost to Make All Characters Equal", + "difficulty": "Medium", + "link": "https://leetcode.com/problems/minimum-deletion-cost-to-make-all-characters-equal/" } } diff --git a/explanations/3774/en.md b/explanations/3774/en.md index be5856f..9600b40 100644 --- a/explanations/3774/en.md +++ b/explanations/3774/en.md @@ -2,58 +2,59 @@ ### Strategy (The "Why") -**Restate the problem:** We need to find the absolute difference between the sum of the k largest elements and the sum of the k smallest elements in an array. +**Restate the problem:** We are given an integer array `nums` and an integer `k`. We need to find the absolute difference between the sum of the k largest elements and the sum of the k smallest elements. **1.1 Constraints & Complexity:** -- **Input Size:** The array length n is at most 100, and each element is between 1 and 100. k is between 1 and n. -- **Time Complexity:** O(n log n) - dominated by sorting the array. -- **Space Complexity:** O(n) for the sorted array. -- **Edge Case:** If k equals the array length, we're comparing the sum of all elements with itself, so the difference is 0. +- **Input Size:** Up to 100 elements in the array, each value between 1 and 100. +- **Time Complexity:** O(n log n) where n is the length of nums - we need to sort the array, which dominates the time complexity. +- **Space Complexity:** O(1) if we sort in-place, or O(n) if we create a sorted copy. +- **Edge Case:** If k equals the array length, we're comparing the sum of all elements with itself, so the result is 0. **1.2 High-level approach:** -The goal is to sort the array, then calculate the sum of the first k elements (smallest) and the sum of the last k elements (largest), and return their absolute difference. - -![Array sorting and selection visualization](https://assets.leetcode.com/static_assets/others/array-sorting.png) +The goal is to sort the array, then take the k largest elements (from the end) and k smallest elements (from the beginning), sum them separately, and return the absolute difference. **1.3 Brute force vs. optimized strategy:** -- **Brute Force:** Find k largest and k smallest elements without sorting, which would require multiple passes and be O(n*k) time. -- **Optimized Strategy:** Sort the array once in O(n log n) time, then directly access the first k and last k elements. This is simpler and efficient for the given constraints. -- **Optimization:** Sorting allows us to easily identify the k smallest (first k) and k largest (last k) elements in a single operation. +- **Brute Force:** Find the k largest and k smallest elements by scanning the array multiple times, which would be O(n × k) time. +- **Optimized Strategy:** Sort the array once, then directly access the first k and last k elements. This is O(n log n) time. +- **Optimization:** Sorting allows us to efficiently access the k smallest and k largest elements in sorted order, making the solution simple and efficient. **1.4 Decomposition:** 1. Sort the array in ascending order. -2. Calculate the sum of the first k elements (smallest k). -3. Calculate the sum of the last k elements (largest k). +2. Calculate the sum of the k smallest elements (first k elements). +3. Calculate the sum of the k largest elements (last k elements). 4. Return the absolute difference between these two sums. ### Steps (The "How") **2.1 Initialization & Example Setup:** -Let's use the example: `nums = [5, 2, 2, 4]`, `k = 2`. +Let's use the example: `nums = [5, 2, 2, 4]`, `k = 2` -- After sorting: `sorted_nums = [2, 2, 4, 5]` +- Original array: `[5, 2, 2, 4]` +- After sorting: `[2, 2, 4, 5]` **2.2 Start Processing:** -We calculate the sums of the smallest and largest k elements. +We sort the array to easily access the smallest and largest elements. **2.3 Trace Walkthrough:** -| Step | Operation | Values | Result | -|------|-----------|--------|--------| -| 1 | Sort array | [5, 2, 2, 4] | [2, 2, 4, 5] | -| 2 | Sum of k smallest | sorted_nums[:2] = [2, 2] | 2 + 2 = 4 | -| 3 | Sum of k largest | sorted_nums[2:] = [4, 5] | 4 + 5 = 9 | -| 4 | Absolute difference | \|9 - 4\| | 5 | +| Step | Operation | Value | Description | +| ---- | --------- | ----- | ----------- | +| 1 | Sort array | `[2, 2, 4, 5]` | Sort in ascending order | +| 2 | k smallest | `[2, 2]` | First k=2 elements | +| 3 | Sum smallest | `2 + 2 = 4` | Sum of k smallest | +| 4 | k largest | `[4, 5]` | Last k=2 elements | +| 5 | Sum largest | `4 + 5 = 9` | Sum of k largest | +| 6 | Difference | `abs(9 - 4) = 5` | Absolute difference | **2.4 Increment and Loop:** -The calculation is straightforward after sorting - no loops needed for the sum calculation. +This is a single-pass operation after sorting, with no additional loop needed. **2.5 Return Result:** diff --git a/explanations/3775/en.md b/explanations/3775/en.md index 1d8d273..fc5e9e9 100644 --- a/explanations/3775/en.md +++ b/explanations/3775/en.md @@ -2,60 +2,61 @@ ### Strategy (The "Why") -**Restate the problem:** We need to count the vowels in the first word, then reverse each subsequent word that has the same vowel count as the first word. Words are separated by single spaces. +**Restate the problem:** We are given a string of lowercase English words separated by single spaces. We need to count the vowels in the first word, then reverse each following word that has the same vowel count. Vowels are 'a', 'e', 'i', 'o', and 'u'. **1.1 Constraints & Complexity:** -- **Input Size:** The string length can be up to 10^5 characters. -- **Time Complexity:** O(n) where n is the string length - we iterate through the string once to split and process words. -- **Space Complexity:** O(n) for storing the words array and result. -- **Edge Case:** If there's only one word, no words need to be reversed, so we return the original string. +- **Input Size:** The string can be up to 10^5 characters long. +- **Time Complexity:** O(n) where n is the length of the string - we process each character once to count vowels and reverse words. +- **Space Complexity:** O(n) to store the words and result string. +- **Edge Case:** If there's only one word, we return it unchanged since there are no following words to process. **1.2 High-level approach:** -The goal is to process words sequentially: count vowels in the first word, then for each subsequent word, check if it has the same vowel count and reverse it if so. - -![Word processing visualization](https://assets.leetcode.com/static_assets/others/word-processing.png) +The goal is to split the string into words, count vowels in the first word, then for each subsequent word, check if it has the same vowel count and reverse it if it does. **1.3 Brute force vs. optimized strategy:** -- **Brute Force:** Process each word multiple times, counting vowels separately for comparison and reversal, which would be less efficient. -- **Optimized Strategy:** Split the string into words once, count vowels in the first word, then iterate through remaining words, counting vowels and reversing when needed. This is O(n) time. -- **Optimization:** By processing words in a single pass and reusing the vowel counting logic, we avoid redundant operations. +- **Brute Force:** For each word after the first, count its vowels and compare with the first word's count, then reverse if needed. This is O(n) time which is already optimal. +- **Optimized Strategy:** Same approach - split into words, count vowels in first word, then process remaining words. This is O(n) time. +- **Optimization:** By splitting once and processing words sequentially, we avoid multiple string scans and make the solution straightforward. **1.4 Decomposition:** 1. Split the string into words. 2. Count vowels in the first word. -3. For each subsequent word, count its vowels. -4. If the vowel count matches the first word's count, reverse the word. -5. Join all words back into a string. +3. For each remaining word: + - Count its vowels. + - If the count matches the first word's count, reverse the word. + - Otherwise, keep it unchanged. +4. Join all words back together with spaces. ### Steps (The "How") **2.1 Initialization & Example Setup:** -Let's use the example: `s = "cat and mice"`. +Let's use the example: `s = "cat and mice"` -- Words: ["cat", "and", "mice"] -- First word: "cat" has 1 vowel ('a') +- Words: `["cat", "and", "mice"]` +- First word: `"cat"` with 1 vowel ('a') +- Result list: `["cat"]` **2.2 Start Processing:** -We process each word after the first one, checking vowel counts and reversing when needed. +We begin processing words from the second word onwards. **2.3 Trace Walkthrough:** -| Word | Vowel Count | Matches First? | Action | Result | -|------|-------------|----------------|--------|--------| -| "cat" | 1 | - | Keep as is | "cat" | -| "and" | 1 | Yes | Reverse | "dna" | -| "mice" | 2 | No | Keep as is | "mice" | +| Step | Word | Vowel Count | Matches First? | Action | Result List | +| ---- | ---- | ----------- | -------------- | ------ | ----------- | +| 1 | "cat" | 1 | N/A (first word) | Keep as is | `["cat"]` | +| 2 | "and" | 1 | Yes | Reverse to "dna" | `["cat", "dna"]` | +| 3 | "mice" | 2 | No | Keep as is | `["cat", "dna", "mice"]` | **2.4 Increment and Loop:** -After processing all words, we join them with spaces. +After processing each word, we move to the next word. We continue until all words are processed. **2.5 Return Result:** -The result is `"cat dna mice"`, where "and" (1 vowel) was reversed to "dna" because it matches the first word's vowel count, while "mice" (2 vowels) remained unchanged. +The result is `"cat dna mice"`, where "and" was reversed to "dna" because it has the same vowel count (1) as "cat". diff --git a/explanations/3776/en.md b/explanations/3776/en.md index 03b4a90..9bb80ad 100644 --- a/explanations/3776/en.md +++ b/explanations/3776/en.md @@ -2,64 +2,70 @@ ### Strategy (The "Why") -**Restate the problem:** We have a circular array where each person has a balance. In one move, a person can transfer exactly 1 unit to either neighbor. We need to find the minimum moves to make all balances non-negative. If impossible, return -1. +**Restate the problem:** We are given a circular array `balance` where `balance[i]` is the net balance of person i. In one move, a person can transfer exactly 1 unit to either their left or right neighbor. We need to find the minimum number of moves required so that every person has a non-negative balance. If impossible, return -1. **1.1 Constraints & Complexity:** -- **Input Size:** The array length n can be up to 10^5, and each balance can be between -10^9 and 10^9. -- **Time Complexity:** O(n log n) - we need to sort positive balances by distance, which dominates the complexity. -- **Space Complexity:** O(n) for storing positive balances with their distances. -- **Edge Case:** If the total sum is negative, it's impossible to make all balances non-negative, so return -1. +- **Input Size:** Up to 10^5 elements in the array. +- **Time Complexity:** O(n) where n is the length - we find the negative index once, then expand outward at most n/2 steps. +- **Space Complexity:** O(1) - we only use a few variables. +- **Edge Case:** If all balances are already non-negative, return 0. If the total sum is negative, return -1. **1.2 High-level approach:** -The goal is to transfer balance from positive positions to the negative position, using the nearest positive balances first to minimize the total transfer distance (and thus moves). - -![Circular array balance transfer visualization](https://assets.leetcode.com/static_assets/others/circular-array.png) +The goal is to find the index with negative balance, then greedily transfer from neighbors at increasing distances until the negative balance is covered. We expand outward from the negative index, using the closest positive balances first. **1.3 Brute force vs. optimized strategy:** - **Brute Force:** Try all possible sequences of transfers, which would be exponential and too slow. -- **Optimized Strategy:** Use a greedy approach: find the negative balance, collect all positive balances with their distances from the negative position, sort by distance, and greedily transfer from nearest to farthest. This is O(n log n) time. -- **Optimization:** By always using the nearest available positive balance first, we minimize the total distance traveled, which directly minimizes the number of moves needed. +- **Optimized Strategy:** Find the negative index, then expand outward distance by distance, transferring from neighbors at each distance. This is O(n) time. +- **Optimization:** By expanding outward from the negative index, we minimize the transfer distance. The cost is transfer_amount × distance, so using closer neighbors first minimizes the total cost. **1.4 Decomposition:** -1. Check if total sum is negative - if so, return -1. -2. Find the index with negative balance. -3. If no negative balance exists, return 0. -4. Collect all positive balances with their circular distances from the negative position. -5. Sort positive balances by distance. -6. Greedily transfer from nearest positives until the negative balance is covered. -7. Return the total moves (sum of transfer_amount * distance). +1. Find the index with negative balance (there's at most one). +2. If all balances are non-negative, return 0. +3. If total sum is negative, return -1 (impossible). +4. Expand outward from the negative index: + - At distance d, get storage from neighbors at positions (j+d) and (j-d) modulo n. + - Transfer the minimum of the debt and available storage. + - Add transfer × distance to the result. + - Update the balance at the negative index. +5. Continue until the negative balance is covered. ### Steps (The "How") **2.1 Initialization & Example Setup:** -Let's use the example: `balance = [5, 1, -4]`, `n = 3`. +Let's use the example: `balance = [5, 1, -4]` -- Total sum: 5 + 1 + (-4) = 2 (non-negative, so possible) -- Negative balance at index 2, amount: 4 -- Positive balances: index 0 (amount 5, distance 1), index 1 (amount 1, distance 1) +- Negative index: `j = 2` (balance[2] = -4) +- Total sum: 5 + 1 + (-4) = 2 (positive, so possible) +- Distance `d = 0` initially **2.2 Start Processing:** -We calculate distances and sort positive balances. +We begin expanding outward from the negative index. **2.3 Trace Walkthrough:** -| Positive Index | Amount | Distance from Index 2 | Sorted Order | -|----------------|--------|----------------------|--------------| -| 0 | 5 | min(\|0-2\|, 3-\|0-2\|) = min(2, 1) = 1 | 1st (tie) | -| 1 | 1 | min(\|1-2\|, 3-\|1-2\|) = min(1, 2) = 1 | 1st (tie) | +| Step | d | Neighbors | Storage | Debt | Transfer | Cost | Balance at j | +| ---- | - | --------- | ------- | ---- | -------- | ---- | ------------- | +| 1 | 1 | (2+1)%3=0, (2-1)%3=1 | 5 + 1 = 6 | 4 | min(4, 6) = 4 | 4 × 1 = 4 | -4 + 4 = 0 | -We need 4 units total. We can take from index 0 (distance 1): transfer 4 units, cost = 4 * 1 = 4 moves. +At distance 1: +- Neighbor at (2+1) % 3 = 0: balance[0] = 5 +- Neighbor at (2-1) % 3 = 1: balance[1] = 1 +- Total storage: 5 + 1 = 6 +- Debt: 4 +- Transfer: min(4, 6) = 4 +- Cost: 4 × 1 = 4 +- New balance at j: -4 + 4 = 0 **2.4 Increment and Loop:** -After transferring from all necessary positive positions, we calculate the total moves. +We increment the distance and continue until the negative balance is covered. **2.5 Return Result:** -The result is 4, which is the minimum number of moves needed. We transfer 4 units from index 0 (distance 1) to index 2, requiring 4 moves. +The result is 4, which is the minimum number of moves required. We transfer 4 units from the neighbors at distance 1, with a cost of 4 moves. diff --git a/explanations/3779/en.md b/explanations/3779/en.md new file mode 100644 index 0000000..cc2932b --- /dev/null +++ b/explanations/3779/en.md @@ -0,0 +1,68 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** We are given an integer array. In one operation, we remove the first three elements (or all remaining if fewer than three). We repeat until the array is empty or contains no duplicate values. We need to find the minimum number of operations required. + +**1.1 Constraints & Complexity:** + +- **Input Size:** Up to 10^5 elements in the array. +- **Time Complexity:** O(n) where n is the length of the array - we process from right to left once. +- **Space Complexity:** O(n) to store the set of seen elements. +- **Edge Case:** If all elements are already distinct, we return 0 without any operations. + +**1.2 High-level approach:** + +The goal is to process the array from right to left, tracking which elements we've seen. If we encounter a duplicate while going right to left, we know we need to remove elements from the left. The number of operations needed is calculated based on how many elements remain. + +**1.3 Brute force vs. optimized strategy:** + +- **Brute Force:** Simulate the operations step by step, removing first 3 elements each time and checking for duplicates. This could be O(n^2) in worst case. +- **Optimized Strategy:** Process from right to left, use a set to track seen elements. When we find a duplicate, calculate operations needed: (remaining elements + 2) // 3. This is O(n) time. +- **Optimization:** By processing from right to left, we can determine the answer without actually performing the removals, making the solution much more efficient. + +**1.4 Decomposition:** + +1. Process the array from right to left. +2. Use a set to track elements we've seen. +3. For each element from right to left: + - If it's already in the set, we found a duplicate. + - Calculate operations needed: (remaining elements + 2) // 3. + - Return the calculated operations. +4. If no duplicates found, return 0. + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** + +Let's use the example: `nums = [3, 8, 3, 6, 5, 8]` + +- Start from right: `8` (last element) +- Seen set: `{8}` +- Process right to left + +**2.2 Start Processing:** + +We begin processing from the rightmost element, adding each to the seen set. + +**2.3 Trace Walkthrough:** + +| Step | Element | In Seen? | Action | Seen Set | Remaining Elements | +| ---- | ------- | -------- | ------ | -------- | ------------------ | +| 1 | 8 (rightmost) | No | Add to seen | `{8}` | 5 | +| 2 | 5 | No | Add to seen | `{8, 5}` | 4 | +| 3 | 6 | No | Add to seen | `{8, 5, 6}` | 3 | +| 4 | 3 | No | Add to seen | `{8, 5, 6, 3}` | 2 | +| 5 | 8 | Yes | Found duplicate! | `{8, 5, 6, 3}` | 2 | +| 6 | Calculate | - | `(2 + 2) // 3 = 1` | - | - | + +When we find duplicate 8 at position 1 (0-indexed), we have 2 elements remaining (indices 0 and 1). Operations needed: (2 + 2) // 3 = 1. + +**2.4 Increment and Loop:** + +We continue processing from right to left until we find a duplicate or finish processing all elements. + +**2.5 Return Result:** + +The result is 1, meaning we need 1 operation to remove the first 3 elements, leaving `[6, 5, 8]` which are all distinct. + diff --git a/explanations/3780/en.md b/explanations/3780/en.md new file mode 100644 index 0000000..e506112 --- /dev/null +++ b/explanations/3780/en.md @@ -0,0 +1,69 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** We are given an integer array. We need to choose exactly three integers such that their sum is divisible by 3, and return the maximum possible sum. If no such triplet exists, return 0. + +**1.1 Constraints & Complexity:** + +- **Input Size:** Up to 10^5 elements in the array. +- **Time Complexity:** O(n log n) where n is the length of nums - we need to sort the numbers by remainder groups, which takes O(n log n). +- **Space Complexity:** O(n) to store the three remainder groups. +- **Edge Case:** If there are fewer than 3 numbers, or no valid combination exists, we return 0. + +**1.2 High-level approach:** + +The goal is to group numbers by their remainder when divided by 3 (0, 1, or 2), then find the maximum sum from valid combinations: three 0s, three 1s, three 2s, or one from each group. + +**1.3 Brute force vs. optimized strategy:** + +- **Brute Force:** Try all possible triplets, check if sum is divisible by 3, and track the maximum. This would be O(n^3) which is too slow for large inputs. +- **Optimized Strategy:** Group by remainder, sort each group in descending order, then check the four valid combinations. This is O(n log n) time. +- **Optimization:** By grouping by remainder, we reduce the problem to checking only 4 specific combinations instead of all possible triplets, making it much more efficient. + +**1.4 Decomposition:** + +1. Group numbers by their remainder when divided by 3 (remainder 0, 1, or 2). +2. Sort each group in descending order. +3. Check four valid combinations: + - Three numbers with remainder 0. + - Three numbers with remainder 1. + - Three numbers with remainder 2. + - One number from each remainder group (0, 1, 2). +4. Return the maximum sum from these valid combinations. + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** + +Let's use the example: `nums = [4, 2, 3, 1]` + +- Group by remainder: + - Remainder 0: `[3]` (3 % 3 = 0) + - Remainder 1: `[4, 1]` (4 % 3 = 1, 1 % 3 = 1) + - Remainder 2: `[2]` (2 % 3 = 2) +- After sorting descending: `rem[0] = [3]`, `rem[1] = [4, 1]`, `rem[2] = [2]` + +**2.2 Start Checking:** + +We check each of the four valid combinations to find the maximum sum. + +**2.3 Trace Walkthrough:** + +| Combination | Numbers | Sum | Valid? | Result | +| ----------- | ------- | --- | ------ | ------ | +| Three 0s | Need 3, have 1 | - | No | - | +| Three 1s | Need 3, have 2 | - | No | - | +| Three 2s | Need 3, have 1 | - | No | - | +| One from each | 3, 4, 2 | 3 + 4 + 2 = 9 | Yes | 9 | + +The only valid combination is one from each remainder group: 3 (rem 0) + 4 (rem 1) + 2 (rem 2) = 9, which is divisible by 3. + +**2.4 Increment and Loop:** + +We check all four combinations and track the maximum valid sum. + +**2.5 Return Result:** + +The result is 9, which is the maximum sum of three numbers (3, 4, 2) whose sum is divisible by 3. + diff --git a/explanations/3781/en.md b/explanations/3781/en.md new file mode 100644 index 0000000..0963cdc --- /dev/null +++ b/explanations/3781/en.md @@ -0,0 +1,65 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** We are given an integer array `nums` and a binary string `s` of the same length. Initially, score is 0. Each index where `s[i] = '1'` contributes `nums[i]` to the score. We can swap '0' and '1' if they are adjacent and '0' is before '1' (swap "01" to "10"). We can do this any number of times. We need to find the maximum possible score. + +**1.1 Constraints & Complexity:** + +- **Input Size:** Up to 10^5 elements in the array. +- **Time Complexity:** O(n log n) where n is the length - we use a max heap which takes O(log n) per operation. +- **Space Complexity:** O(n) for the heap storage. +- **Edge Case:** If all characters in `s` are '0', the score is 0 and no swaps are possible. + +**1.2 High-level approach:** + +The goal is to use a greedy approach with a max heap. As we process from left to right, we add all numbers to a heap. When we encounter a '1', we take the maximum value from the heap and add it to our score. This maximizes the score because we always use the largest available number when forced to select. + +**1.3 Brute force vs. optimized strategy:** + +- **Brute Force:** Try all possible sequences of swaps, calculate the score for each, and find the maximum. This would be exponential and too slow. +- **Optimized Strategy:** Use a max heap to track all numbers seen so far. When we must select (at a '1'), always choose the maximum. This is O(n log n) time. +- **Optimization:** The key insight is that we can effectively "move" '1's backward by swapping, so when we see a '1', we want to use the best number we've seen so far. The heap allows us to efficiently get the maximum. + +**1.4 Decomposition:** + +1. Initialize a max heap (using negative values for Python's min heap). +2. Process the array from left to right: + - Add each number to the heap. + - If the current character is '1', pop the maximum from the heap and add it to the score. +3. Return the total score. + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** + +Let's use the example: `nums = [2, 1, 5, 2, 3]`, `s = "01010"` + +- Heap: `[]` (empty) +- Score `res = 0` +- Process indices 0 to 4 + +**2.2 Start Processing:** + +We begin processing from left to right, adding numbers to the heap. + +**2.3 Trace Walkthrough:** + +| Step | Index | nums[i] | s[i] | Heap (max first) | Action | res | +| ---- | ----- | ------- | ---- | ---------------- | ------ | --- | +| 1 | 0 | 2 | '0' | `[2]` | Add to heap | 0 | +| 2 | 1 | 1 | '1' | `[2, 1]` | Add to heap, then pop max (2) | 2 | +| 3 | 2 | 5 | '0' | `[5, 1]` | Add to heap | 2 | +| 4 | 3 | 2 | '1' | `[5, 2, 1]` | Add to heap, then pop max (5) | 7 | +| 5 | 4 | 3 | '0' | `[3, 2, 1]` | Add to heap | 7 | + +Final score: 2 + 5 = 7 + +**2.4 Increment and Loop:** + +After processing each index, we move to the next. We continue until all indices are processed. + +**2.5 Return Result:** + +The result is 7, which is the maximum score achievable by selecting the largest available numbers (2 and 5) when we encounter '1's in the string. + diff --git a/explanations/3783/en.md b/explanations/3783/en.md new file mode 100644 index 0000000..85dbce5 --- /dev/null +++ b/explanations/3783/en.md @@ -0,0 +1,62 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** We are given an integer n. We need to calculate its mirror distance, which is the absolute difference between the number and its reverse (the number formed by reversing its digits). + +**1.1 Constraints & Complexity:** + +- **Input Size:** The integer n can be up to 10^9, which means up to 10 digits. +- **Time Complexity:** O(log n) - we convert the number to a string (which takes O(log n) time for the number of digits), reverse it, and convert back. +- **Space Complexity:** O(log n) - we store the string representation which has length proportional to log n. +- **Edge Case:** If n is a single digit or a palindrome (like 7 or 121), the mirror distance is 0. + +**1.2 High-level approach:** + +The goal is to reverse the digits of the number and calculate the absolute difference between the original and reversed numbers. + +**1.3 Brute force vs. optimized strategy:** + +- **Brute Force:** Extract digits one by one using modulo and division, build the reverse number digit by digit, then calculate the difference. This is O(log n) time and O(1) space. +- **Optimized Strategy:** Convert to string, reverse the string, convert back to integer, then calculate absolute difference. This is also O(log n) time but more readable. +- **Optimization:** Using string reversal is simpler and more intuitive, making the code easier to understand and maintain. + +**1.4 Decomposition:** + +1. Convert the integer to a string representation. +2. Reverse the string. +3. Convert the reversed string back to an integer. +4. Calculate and return the absolute difference between the original and reversed numbers. + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** + +Let's use the example: `n = 25` + +- Original number: `25` +- String representation: `"25"` +- Reversed string: `"52"` +- Reversed number: `52` + +**2.2 Start Processing:** + +We convert the number to a string and reverse it. + +**2.3 Trace Walkthrough:** + +| Step | Operation | Value | Description | +| ---- | --------- | ----- | ----------- | +| 1 | Convert to string | `"25"` | Convert integer 25 to string | +| 2 | Reverse string | `"52"` | Reverse the string characters | +| 3 | Convert to int | `52` | Convert reversed string back to integer | +| 4 | Calculate difference | `abs(25 - 52) = 27` | Calculate absolute difference | + +**2.4 Increment and Loop:** + +This is a single-pass operation with no loop needed. + +**2.5 Return Result:** + +The result is 27, which is the absolute difference between 25 and its reverse 52. + diff --git a/explanations/3784/en.md b/explanations/3784/en.md new file mode 100644 index 0000000..33fd8b5 --- /dev/null +++ b/explanations/3784/en.md @@ -0,0 +1,71 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** We are given a string `s` and an integer array `cost` of the same length, where `cost[i]` is the cost to delete the i-th character. We can delete any number of characters such that the resulting string is non-empty and consists of equal characters. We need to find the minimum total deletion cost. + +**1.1 Constraints & Complexity:** + +- **Input Size:** Up to 10^5 characters in the string. +- **Time Complexity:** O(n) where n is the length of the string - we iterate through the string once to sum costs for each character. +- **Space Complexity:** O(1) if we use a dictionary with at most 26 keys (for lowercase letters), effectively O(1). +- **Edge Case:** If all characters are already equal, we don't need to delete anything, so the cost is 0. + +**1.2 High-level approach:** + +The goal is to find which character has the maximum total deletion cost (meaning it's most expensive to delete), then keep that character and delete all others. This minimizes the total cost because we avoid deleting the most expensive character. + +**1.3 Brute force vs. optimized strategy:** + +- **Brute Force:** Try keeping each possible character, calculate the cost of deleting all others, and find the minimum. This is O(n) for each character, so O(26n) = O(n) which is already efficient. +- **Optimized Strategy:** Sum costs for each character, find the character with maximum total cost, then return total cost minus that maximum. This is O(n) time. +- **Optimization:** By finding the character with maximum deletion cost and keeping it, we minimize the total cost we need to pay. The answer is simply total cost minus the maximum character cost. + +**1.4 Decomposition:** + +1. Sum up the deletion costs for each character in the string. +2. Find the character with the maximum total deletion cost. +3. Keep that character and delete all others. +4. Return the total cost minus the maximum character cost (this is the cost of deleting all other characters). + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** + +Let's use the example: `s = "aabaac"`, `cost = [1, 2, 3, 4, 1, 10]` + +- Character cost mapping: + - 'a': 1 + 2 + 4 + 1 = 8 + - 'b': 3 + - 'c': 10 +- Total cost: 1 + 2 + 3 + 4 + 1 + 10 = 21 + +**2.2 Start Processing:** + +We iterate through the string and sum costs for each character. + +**2.3 Trace Walkthrough:** + +| Step | Character | Cost | Running Total for Character | Total Cost | +| ---- | --------- | ---- | --------------------------- | ---------- | +| 1 | 'a' | 1 | a: 1 | 1 | +| 2 | 'a' | 2 | a: 3 | 3 | +| 3 | 'b' | 3 | b: 3 | 6 | +| 4 | 'a' | 4 | a: 7 | 10 | +| 5 | 'a' | 1 | a: 8 | 11 | +| 6 | 'c' | 10 | c: 10 | 21 | + +After processing: +- 'a' total cost: 8 +- 'b' total cost: 3 +- 'c' total cost: 10 (maximum) +- Keep 'c', delete others: 21 - 10 = 11 + +**2.4 Increment and Loop:** + +We continue processing each character until we've processed the entire string. + +**2.5 Return Result:** + +The result is 11, which is the minimum cost to delete all characters except 'c' (the character with maximum deletion cost). + diff --git a/explanations/57/en.md b/explanations/57/en.md index 62ebe39..e91eb03 100644 --- a/explanations/57/en.md +++ b/explanations/57/en.md @@ -1,97 +1,61 @@ -You are given an array of non-overlapping intervals `intervals` where `intervals[i] = [start_i, end_i]` represent the start and the end of the `i^th` interval and `intervals` is sorted in ascending order by `start_i`. You are also given an interval `newInterval = [start, end]` that represents the start and end of another interval. - -Insert `newInterval` into `intervals` such that `intervals` is still sorted in ascending order by `start_i` and `intervals` still does not have any overlapping intervals (merge overlapping intervals if necessary). - -Return `intervals` *after the insertion*. - -**Note** that you don't need to modify `intervals` in-place. You can make a new array and return it. - -**Example 1:** - -```sh -Input: intervals = [[1,3],[6,9]], newInterval = [2,5] -Output: [[1,5],[6,9]] -``` - -**Example 2:** - -```sh -Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8] -Output: [[1,2],[3,10],[12,16]] -Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10]. -``` - -**Constraints:** +## Explanation -- `0 <= intervals.length <= 10^4` -- `intervals[i].length == 2` -- `0 <= start_i <= end_i <= 10^5` -- `intervals` is sorted by `start_i` in **ascending** order. -- `newInterval.length == 2` -- `0 <= start <= end <= 10^5` +### Strategy (The "Why") -## Explanation +**Restate the problem:** We are given a sorted array of non-overlapping intervals and a new interval. We need to insert the new interval into the array such that the result remains sorted and all overlapping intervals are merged. -### Strategy +**1.1 Constraints & Complexity:** -This is an **array manipulation problem** that requires inserting a new interval into a sorted list of non-overlapping intervals. The key insight is to process intervals in three phases: before overlap, during overlap, and after overlap. +- **Input Size:** Up to 10^4 intervals, each with start and end values up to 10^5. +- **Time Complexity:** O(n) where n is the number of intervals. We traverse the array once, processing each interval at most once. +- **Space Complexity:** O(n) to store the result array. +- **Edge Case:** If the intervals array is empty, we return an array containing only the new interval. -**Key observations:** -- Intervals are already sorted by start time -- We need to find where the new interval fits -- We may need to merge multiple overlapping intervals -- Process intervals in three phases based on overlap with new interval +**1.2 High-level approach:** -**High-level approach:** -1. **Add intervals before overlap**: Add all intervals that end before new interval starts -2. **Merge overlapping intervals**: Find all intervals that overlap with new interval -3. **Add merged interval**: Add the final merged interval -4. **Add remaining intervals**: Add all intervals that start after new interval ends +The goal is to process intervals in three phases: add intervals that come before the new interval, merge all intervals that overlap with the new interval, and add the remaining intervals that come after. -### Steps +**1.3 Brute force vs. optimized strategy:** -Let's break down the solution step by step: +- **Brute Force:** Insert the new interval, sort the entire array, then merge overlapping intervals. This would be O(n log n) time due to sorting. +- **Optimized Strategy:** Since intervals are already sorted, we can process them in a single pass: add intervals before overlap, merge overlapping ones, then add remaining intervals. This is O(n) time. +- **Optimization:** By leveraging the fact that intervals are already sorted, we avoid the need for sorting and can process everything in one pass, making the solution more efficient. -**Step 1: Initialize result list** -- Create empty result list: `result = []` +**1.4 Decomposition:** -**Step 2: Add intervals before overlap** -- Add all intervals where `interval[1] < newInterval[0]` +1. Add all intervals that end before the new interval starts (no overlap). +2. Merge all intervals that overlap with the new interval by updating the start and end boundaries. +3. Add the merged interval to the result. +4. Add all remaining intervals that start after the merged interval ends. -**Step 3: Merge overlapping intervals** -- Find all intervals that overlap with new interval -- Update new interval boundaries: `start = min(start, interval[0])`, `end = max(end, interval[1])` +### Steps (The "How") -**Step 4: Add merged interval** -- Add the final merged interval to result +**2.1 Initialization & Example Setup:** -**Step 5: Add remaining intervals** -- Add all intervals where `interval[0] > newInterval[1]` +Let's use the example: `intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]]`, `newInterval = [4,8]` -**Example walkthrough:** -Let's trace through the second example: +- Result array: `res = []` +- Index `i = 0` +- New interval boundaries: `start = 4`, `end = 8` -```sh -intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8] +**2.2 Start Processing:** -Step 1: Add intervals before overlap -result = [[1,2]] (3,5 overlaps, so stop) +We begin processing intervals from left to right, checking each interval's relationship with the new interval. -Step 2: Merge overlapping intervals -Overlap with [3,5]: newInterval = [min(4,3), max(8,5)] = [3,8] -Overlap with [6,7]: newInterval = [min(3,6), max(8,7)] = [3,8] -Overlap with [8,10]: newInterval = [min(3,8), max(8,10)] = [3,10] +**2.3 Trace Walkthrough:** -Step 3: Add merged interval -result = [[1,2],[3,10]] +| Step | i | Interval | Condition | Action | res | start, end | +| ---- | - | -------- | --------- | ------ | --- | ---------- | +| 1 | 0 | [1,2] | 2 < 4 (ends before) | Add to res | `[[1,2]]` | 4, 8 | +| 2 | 1 | [3,5] | 3 <= 8 (overlaps) | Merge: start=min(4,3)=3, end=max(8,5)=8 | `[[1,2]]` | 3, 8 | +| 3 | 2 | [6,7] | 6 <= 8 (overlaps) | Merge: start=min(3,6)=3, end=max(8,7)=8 | `[[1,2]]` | 3, 8 | +| 4 | 3 | [8,10] | 8 <= 8 (overlaps) | Merge: start=min(3,8)=3, end=max(8,10)=10 | `[[1,2]]` | 3, 10 | +| 5 | 4 | [12,16] | 12 > 10 (starts after) | Add merged [3,10], then add [12,16] | `[[1,2],[3,10],[12,16]]` | - | -Step 4: Add remaining intervals -result = [[1,2],[3,10],[12,16]] +**2.4 Increment and Loop:** -Result: [[1,2],[3,10],[12,16]] -``` +After processing each interval, we increment the index `i` and continue until all intervals are processed. -> **Note:** The key insight is to process intervals in three phases. This approach is efficient because we only need to traverse the array once, and we can determine which phase each interval belongs to by comparing its boundaries with the new interval. +**2.5 Return Result:** -**Time Complexity:** O(n) - we visit each interval at most once -**Space Complexity:** O(n) - to store the result \ No newline at end of file +The result is `[[1,2],[3,10],[12,16]]`, where the new interval [4,8] has been merged with overlapping intervals [3,5], [6,7], and [8,10] to form [3,10]. diff --git a/explanations/955/en.md b/explanations/955/en.md new file mode 100644 index 0000000..3575d49 --- /dev/null +++ b/explanations/955/en.md @@ -0,0 +1,71 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** We are given an array of strings, all of the same length. We can delete any columns (indices) from all strings. After deletion, we want the final array to be in lexicographic order (each string is less than or equal to the next). We need to find the minimum number of columns to delete. + +**1.1 Constraints & Complexity:** + +- **Input Size:** Up to 100 strings, each with up to 100 characters. +- **Time Complexity:** O(M × N) where M is the number of strings and N is the length of each string. We iterate through each column once, and for each column, we check all string pairs. +- **Space Complexity:** O(M) to store the sorted status of each pair of adjacent strings. +- **Edge Case:** If the strings are already in lexicographic order, we don't need to delete any columns, so the answer is 0. + +**1.2 High-level approach:** + +The goal is to greedily decide which columns to keep. We process columns from left to right. For each column, we check if keeping it would break the lexicographic order. If it breaks the order, we delete it. Otherwise, we keep it and update our knowledge of which string pairs are now sorted. + +**1.3 Brute force vs. optimized strategy:** + +- **Brute Force:** Try all possible combinations of columns to delete, check if the resulting strings are sorted, and find the minimum. This would be O(2^N × M × N) which is exponential and too slow. +- **Optimized Strategy:** Use a greedy approach - process columns left to right, track which pairs are already sorted, and only delete a column if it breaks the order. This is O(M × N) time. +- **Optimization:** By tracking which pairs are already sorted, we avoid re-checking pairs that we know are sorted from previous columns. This makes the solution efficient. + +**1.4 Decomposition:** + +1. Initialize a boolean array to track which pairs of adjacent strings are already sorted. +2. For each column from left to right: + - Check if this column would break the lexicographic order for any unsorted pair. + - If it breaks the order, delete the column (increment the result counter). + - If we keep the column, update the sorted status for pairs where this column makes them sorted. +3. Return the total number of deleted columns. + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** + +Let's use the example: `strs = ["ca", "bb", "ac"]` + +- Number of strings `n = 3`, length of each string `m = 2` +- Result `res = 0` +- Sorted pairs array: `sorted_pairs = [False, False]` (we have 2 pairs: "ca"-"bb" and "bb"-"ac") +- We'll process columns: column 0 (first character), then column 1 (second character) + +**2.2 Start Checking:** + +We begin processing columns from left to right. For each column, we check if it breaks the lexicographic order. + +**2.3 Trace Walkthrough:** + +| Step | Column | Check Pair | Comparison | Breaks Order? | Action | res | sorted_pairs | +| ---- | ------ | ---------- | ---------- | ------------- | ------ | --- | ------------ | +| 1 | 0 | "ca"-"bb" | 'c' > 'b' | Yes | Delete column 0 | 1 | [False, False] | +| 2 | 1 | "ca"-"bb" | 'a' < 'b' | No | Keep column 1, update sorted | 1 | [True, False] | +| 2 | 1 | "bb"-"ac" | 'b' < 'c' | No | Keep column 1, update sorted | 1 | [True, True] | + +Detailed execution: +- **Column 0:** Check unsorted pair 0 ("ca" vs "bb" at position 0): 'c' > 'b' breaks order → Delete column 0, res = 1 +- **Column 1:** + - Check unsorted pair 0 ("ca" vs "bb" at position 1): 'a' < 'b' doesn't break → Can keep column 1 + - Check unsorted pair 1 ("bb" vs "ac" at position 1): 'b' < 'c' doesn't break → Can keep column 1 + - Since we keep column 1, update sorted_pairs: pair 0 becomes sorted ('a' < 'b'), pair 1 becomes sorted ('b' < 'c') + - After deleting column 0, the remaining strings are `["a", "b", "c"]` which are sorted + +**2.4 Increment and Loop:** + +After processing each column, we move to the next column. We continue until all columns are processed. + +**2.5 Return Result:** + +The result is 1, which means we need to delete 1 column (the first column) to make the strings lexicographically sorted. + diff --git a/package.json b/package.json index eb1ff8a..9e9e69b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "scripts": { "format:json": "prettier --write 'data/**/*.json'", + "format:python": "black scripts/ solutions/", "prepare": "husky" }, "devDependencies": { diff --git a/requirements.txt b/requirements.txt index 139597f..46ed504 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1 @@ - - +black>=24.0.0 diff --git a/scripts/update_problems_from_leetcode.py b/scripts/update_problems_from_leetcode.py index 9a4871d..98cd784 100755 --- a/scripts/update_problems_from_leetcode.py +++ b/scripts/update_problems_from_leetcode.py @@ -102,10 +102,7 @@ def map_tags_to_category(tags: List[Dict[str, str]]) -> str: elif any("greedy" in t for t in all_tags): return "Greedy" elif any( - "math" in t - or "geometry" in t - or "number-theory" in t - or "combinatorics" in t + "math" in t or "geometry" in t or "number-theory" in t or "combinatorics" in t for t in all_tags ): return "Math & Geometry" @@ -324,4 +321,3 @@ def main(): if __name__ == "__main__": main() - diff --git a/solutions/100/01.py b/solutions/100/01.py index 3106b6e..0a57cf1 100644 --- a/solutions/100/01.py +++ b/solutions/100/01.py @@ -9,14 +9,13 @@ def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool: # Both are None if not p and not q: return True - + # One is None, the other is not if not p or not q: return False - + # Both exist, check values and recursively check children if p.val != q.val: return False - - return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right) + return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right) diff --git a/solutions/1004/01.py b/solutions/1004/01.py index a781515..8d9020c 100644 --- a/solutions/1004/01.py +++ b/solutions/1004/01.py @@ -1,23 +1,24 @@ from typing import List + class Solution: def longestOnes(self, nums: List[int], k: int) -> int: left = 0 max_length = 0 zero_count = 0 - + for right in range(len(nums)): # Expand window if nums[right] == 0: zero_count += 1 - + # Shrink window if zero_count exceeds k while zero_count > k: if nums[left] == 0: zero_count -= 1 left += 1 - + # Update maximum length max_length = max(max_length, right - left + 1) - + return max_length diff --git a/solutions/1008/01.py b/solutions/1008/01.py index 77eedd9..9942659 100644 --- a/solutions/1008/01.py +++ b/solutions/1008/01.py @@ -8,15 +8,15 @@ class Solution: def bstFromPreorder(self, preorder: List[int]) -> Optional[TreeNode]: if not preorder: return None - + root = TreeNode(preorder[0]) - + # Find the split point where values become greater than root i = 1 while i < len(preorder) and preorder[i] < preorder[0]: i += 1 - + root.left = self.bstFromPreorder(preorder[1:i]) root.right = self.bstFromPreorder(preorder[i:]) - + return root diff --git a/solutions/101/01.py b/solutions/101/01.py index ab77743..8a7a786 100644 --- a/solutions/101/01.py +++ b/solutions/101/01.py @@ -5,6 +5,7 @@ # self.left = left # self.right = right + class Solution: def isSymmetric(self, root) -> bool: def is_mirror(left, right): @@ -12,12 +13,13 @@ def is_mirror(left, right): return True if not left or not right: return False - return (left.val == right.val and - is_mirror(left.left, right.right) and - is_mirror(left.right, right.left)) - + return ( + left.val == right.val + and is_mirror(left.left, right.right) + and is_mirror(left.right, right.left) + ) + if not root: return True - - return is_mirror(root.left, root.right) + return is_mirror(root.left, root.right) diff --git a/solutions/102/01.py b/solutions/102/01.py index c1a0464..3f49ce5 100644 --- a/solutions/102/01.py +++ b/solutions/102/01.py @@ -8,28 +8,28 @@ from typing import List from collections import deque + class Solution: def levelOrder(self, root) -> List[List[int]]: if not root: return [] - + res = [] queue = deque([root]) - + while queue: level_size = len(queue) level = [] - + for _ in range(level_size): node = queue.popleft() level.append(node.val) - + if node.left: queue.append(node.left) if node.right: queue.append(node.right) - + res.append(level) - - return res + return res diff --git a/solutions/1029/01.py b/solutions/1029/01.py index 208885b..4eb5ba3 100644 --- a/solutions/1029/01.py +++ b/solutions/1029/01.py @@ -3,15 +3,14 @@ def twoCitySchedCost(self, costs: List[List[int]]) -> int: # Sort by the difference (costA - costB) # This prioritizes people who save more by going to city A costs.sort(key=lambda x: x[0] - x[1]) - + n = len(costs) // 2 res = 0 - + # First n people go to city A, rest go to city B for i in range(n): res += costs[i][0] # City A for i in range(n, len(costs)): res += costs[i][1] # City B - - return res + return res diff --git a/solutions/103/01.py b/solutions/103/01.py index 9514ca5..3e5ecd7 100644 --- a/solutions/103/01.py +++ b/solutions/103/01.py @@ -8,30 +8,29 @@ class Solution: def zigzagLevelOrder(self, root: Optional[TreeNode]) -> List[List[int]]: if not root: return [] - + res = [] queue = [root] left_to_right = True - + while queue: level_size = len(queue) level = [] - + for _ in range(level_size): node = queue.pop(0) level.append(node.val) - + if node.left: queue.append(node.left) if node.right: queue.append(node.right) - + # Reverse if needed for zigzag if not left_to_right: level.reverse() - + res.append(level) left_to_right = not left_to_right - - return res + return res diff --git a/solutions/1038/01.py b/solutions/1038/01.py index 6206375..e2a4b94 100644 --- a/solutions/1038/01.py +++ b/solutions/1038/01.py @@ -7,20 +7,19 @@ class Solution: def bstToGst(self, root: TreeNode) -> TreeNode: total = 0 - + def reverse_inorder(node): nonlocal total if node: # Traverse right first (largest values) reverse_inorder(node.right) - + # Update current node value total += node.val node.val = total - + # Traverse left (smaller values) reverse_inorder(node.left) - + reverse_inorder(root) return root - diff --git a/solutions/104/01.py b/solutions/104/01.py index dd4dfa7..29b575e 100644 --- a/solutions/104/01.py +++ b/solutions/104/01.py @@ -5,15 +5,15 @@ # self.left = left # self.right = right + class Solution: def maxDepth(self, root) -> int: if not root: return 0 - + # Recursively find max depth of left and right subtrees left_depth = self.maxDepth(root.left) right_depth = self.maxDepth(root.right) - + # Return max depth plus 1 for current node return max(left_depth, right_depth) + 1 - diff --git a/solutions/1046/01.py b/solutions/1046/01.py index d25afaa..e43ffab 100644 --- a/solutions/1046/01.py +++ b/solutions/1046/01.py @@ -1,20 +1,19 @@ class Solution: def lastStoneWeight(self, stones: List[int]) -> int: import heapq - + # Use max heap (negate values for min heap) heap = [-stone for stone in stones] heapq.heapify(heap) - + while len(heap) > 1: # Get two heaviest stones y = -heapq.heappop(heap) x = -heapq.heappop(heap) - + # If they're different, add the difference back if x != y: heapq.heappush(heap, -(y - x)) - + # Return last stone weight or 0 return -heap[0] if heap else 0 - diff --git a/solutions/105/01.py b/solutions/105/01.py index a0dfac5..87f22c8 100644 --- a/solutions/105/01.py +++ b/solutions/105/01.py @@ -8,29 +8,30 @@ class Solution: def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: if not preorder or not inorder: return None - + # Create a map for O(1) lookup of inorder indices inorder_map = {val: idx for idx, val in enumerate(inorder)} - + def build(pre_start, pre_end, in_start, in_end): if pre_start > pre_end: return None - + # Root is the first element in preorder root_val = preorder[pre_start] root = TreeNode(root_val) - + # Find root position in inorder root_idx = inorder_map[root_val] - + # Calculate sizes of left and right subtrees left_size = root_idx - in_start - + # Recursively build left and right subtrees - root.left = build(pre_start + 1, pre_start + left_size, in_start, root_idx - 1) + root.left = build( + pre_start + 1, pre_start + left_size, in_start, root_idx - 1 + ) root.right = build(pre_start + left_size + 1, pre_end, root_idx + 1, in_end) - + return root - - return build(0, len(preorder) - 1, 0, len(inorder) - 1) + return build(0, len(preorder) - 1, 0, len(inorder) - 1) diff --git a/solutions/106/01.py b/solutions/106/01.py index ac6b902..fab69c8 100644 --- a/solutions/106/01.py +++ b/solutions/106/01.py @@ -8,29 +8,32 @@ class Solution: def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]: if not inorder or not postorder: return None - + # Create a map for O(1) lookup of inorder indices inorder_map = {val: idx for idx, val in enumerate(inorder)} - + def build(in_start, in_end, post_start, post_end): if in_start > in_end: return None - + # Root is the last element in postorder root_val = postorder[post_end] root = TreeNode(root_val) - + # Find root position in inorder root_idx = inorder_map[root_val] - + # Calculate sizes of left and right subtrees left_size = root_idx - in_start - + # Recursively build left and right subtrees - root.left = build(in_start, root_idx - 1, post_start, post_start + left_size - 1) - root.right = build(root_idx + 1, in_end, post_start + left_size, post_end - 1) - + root.left = build( + in_start, root_idx - 1, post_start, post_start + left_size - 1 + ) + root.right = build( + root_idx + 1, in_end, post_start + left_size, post_end - 1 + ) + return root - - return build(0, len(inorder) - 1, 0, len(postorder) - 1) + return build(0, len(inorder) - 1, 0, len(postorder) - 1) diff --git a/solutions/1079/01.py b/solutions/1079/01.py index c51ed0d..d8a35bc 100644 --- a/solutions/1079/01.py +++ b/solutions/1079/01.py @@ -1,7 +1,7 @@ class Solution: def numTilePossibilities(self, tiles: str) -> int: from collections import Counter - + def backtrack(count): res = 0 for char in count: @@ -11,6 +11,6 @@ def backtrack(count): res += backtrack(count) count[char] += 1 return res - + count = Counter(tiles) return backtrack(count) diff --git a/solutions/108/01.py b/solutions/108/01.py index 9bb01ea..ac6ef04 100644 --- a/solutions/108/01.py +++ b/solutions/108/01.py @@ -1,5 +1,6 @@ from typing import List, Optional + # Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): @@ -11,16 +12,15 @@ def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]: def build(left, right): if left > right: return None - + # Choose middle element as root mid = (left + right) // 2 root = TreeNode(nums[mid]) - + # Recursively build left and right subtrees root.left = build(left, mid - 1) root.right = build(mid + 1, right) - + return root - - return build(0, len(nums) - 1) + return build(0, len(nums) - 1) diff --git a/solutions/11/01.py b/solutions/11/01.py index bd501d7..f7ef9f8 100644 --- a/solutions/11/01.py +++ b/solutions/11/01.py @@ -1,21 +1,22 @@ from typing import List + class Solution: def maxArea(self, height: List[int]) -> int: left = 0 right = len(height) - 1 max_area = 0 - + while left < right: # Calculate current area width = right - left current_area = width * min(height[left], height[right]) max_area = max(max_area, current_area) - + # Move the pointer with smaller height if height[left] < height[right]: left += 1 else: right -= 1 - + return max_area diff --git a/solutions/112/01.py b/solutions/112/01.py index 7baf763..3f42077 100644 --- a/solutions/112/01.py +++ b/solutions/112/01.py @@ -1,5 +1,6 @@ from typing import Optional + # Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): @@ -10,12 +11,13 @@ class Solution: def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: if not root: return False - + # If leaf node, check if value equals remaining sum if not root.left and not root.right: return root.val == targetSum - + # Recursively check left and right subtrees remaining = targetSum - root.val - return self.hasPathSum(root.left, remaining) or self.hasPathSum(root.right, remaining) - + return self.hasPathSum(root.left, remaining) or self.hasPathSum( + root.right, remaining + ) diff --git a/solutions/1127/01.py b/solutions/1127/01.py index f38b775..3ff01a4 100644 --- a/solutions/1127/01.py +++ b/solutions/1127/01.py @@ -1,21 +1,21 @@ from typing import List import heapq + class Solution: def lastStoneWeight(self, stones: List[int]) -> int: # Use max heap (negate values since Python has min heap) heap = [-stone for stone in stones] heapq.heapify(heap) - + while len(heap) > 1: # Get two largest stones first = -heapq.heappop(heap) second = -heapq.heappop(heap) - + # If they're different, add the difference back if first != second: heapq.heappush(heap, -(first - second)) - + # Return the last stone weight, or 0 if no stones left return -heap[0] if heap else 0 - diff --git a/solutions/1137/01.py b/solutions/1137/01.py index bd122d0..5d4481e 100644 --- a/solutions/1137/01.py +++ b/solutions/1137/01.py @@ -4,17 +4,16 @@ def tribonacci(self, n: int) -> int: return 0 if n <= 2: return 1 - + # Use iterative approach prev3 = 0 # T(0) prev2 = 1 # T(1) prev1 = 1 # T(2) - + for i in range(3, n + 1): current = prev1 + prev2 + prev3 prev3 = prev2 prev2 = prev1 prev1 = current - - return prev1 + return prev1 diff --git a/solutions/114/01.py b/solutions/114/01.py index 4c3aa18..79b352d 100644 --- a/solutions/114/01.py +++ b/solutions/114/01.py @@ -1,5 +1,6 @@ from typing import Optional + # Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): @@ -13,21 +14,20 @@ def flatten(self, root: Optional[TreeNode]) -> None: """ if not root: return - + # Flatten left and right subtrees self.flatten(root.left) self.flatten(root.right) - + # Save right subtree right = root.right - + # Move left subtree to right root.right = root.left root.left = None - + # Find the end of the new right subtree and attach saved right curr = root while curr.right: curr = curr.right curr.right = right - diff --git a/solutions/1143/01.py b/solutions/1143/01.py index f8412eb..c16e0f7 100644 --- a/solutions/1143/01.py +++ b/solutions/1143/01.py @@ -1,10 +1,10 @@ class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int: m, n = len(text1), len(text2) - + # dp[i][j] represents the length of LCS of text1[0:i] and text2[0:j] dp = [[0] * (n + 1) for _ in range(m + 1)] - + for i in range(1, m + 1): for j in range(1, n + 1): if text1[i - 1] == text2[j - 1]: @@ -13,6 +13,5 @@ def longestCommonSubsequence(self, text1: str, text2: str) -> int: else: # Characters don't match, take maximum dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) - - return dp[m][n] + return dp[m][n] diff --git a/solutions/116/01.py b/solutions/116/01.py index c927f7f..bc73045 100644 --- a/solutions/116/01.py +++ b/solutions/116/01.py @@ -6,33 +6,33 @@ # self.right = right # self.next = next + class Solution: - def connect(self, root: 'Node') -> 'Node': + def connect(self, root: "Node") -> "Node": if not root: return root - + # Start with the root node leftmost = root - + # While we have a level to process while leftmost.left: # Current node in the current level current = leftmost - + # Iterate through the current level while current: # Connect left child to right child current.left.next = current.right - + # Connect right child to next node's left child (if exists) if current.next: current.right.next = current.next.left - + # Move to next node in the same level current = current.next - + # Move to the next level leftmost = leftmost.left - - return root + return root diff --git a/solutions/1161/01.py b/solutions/1161/01.py index 795a8d6..edea8e8 100644 --- a/solutions/1161/01.py +++ b/solutions/1161/01.py @@ -8,31 +8,31 @@ class Solution: def maxLevelSum(self, root: Optional[TreeNode]) -> int: if not root: return 0 - + from collections import deque + queue = deque([root]) - max_sum = float('-inf') + max_sum = float("-inf") res = 1 level = 1 - + while queue: level_sum = 0 size = len(queue) - + for _ in range(size): node = queue.popleft() level_sum += node.val - + if node.left: queue.append(node.left) if node.right: queue.append(node.right) - + if level_sum > max_sum: max_sum = level_sum res = level - + level += 1 - - return res + return res diff --git a/solutions/1167/01.py b/solutions/1167/01.py index f026369..c40bae6 100644 --- a/solutions/1167/01.py +++ b/solutions/1167/01.py @@ -1,21 +1,20 @@ class Solution: def connectSticks(self, sticks: List[int]) -> int: import heapq - + heapq.heapify(sticks) res = 0 - + while len(sticks) > 1: # Get two shortest sticks first = heapq.heappop(sticks) second = heapq.heappop(sticks) - + # Cost is sum of two sticks cost = first + second res += cost - + # Add merged stick back heapq.heappush(sticks, cost) - - return res + return res diff --git a/solutions/117/01.py b/solutions/117/01.py index 046f6b3..152b148 100644 --- a/solutions/117/01.py +++ b/solutions/117/01.py @@ -10,28 +10,28 @@ def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next self.next = next """ + class Solution: - def connect(self, root: 'Node') -> 'Node': + def connect(self, root: "Node") -> "Node": if not root: return root - + queue = deque([root]) - + while queue: level_size = len(queue) prev = None - + for _ in range(level_size): node = queue.popleft() - + if prev: prev.next = node prev = node - + if node.left: queue.append(node.left) if node.right: queue.append(node.right) - - return root + return root diff --git a/solutions/12/01.py b/solutions/12/01.py index d2c09e4..d1506f9 100644 --- a/solutions/12/01.py +++ b/solutions/12/01.py @@ -2,15 +2,28 @@ class Solution: def intToRoman(self, num: int) -> str: # Map of values to Roman symbols values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1] - symbols = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"] - + symbols = [ + "M", + "CM", + "D", + "CD", + "C", + "XC", + "L", + "XL", + "X", + "IX", + "V", + "IV", + "I", + ] + res = "" - + # Greedily subtract largest possible values for i in range(len(values)): count = num // values[i] res += symbols[i] * count num %= values[i] - - return res + return res diff --git a/solutions/120/01.py b/solutions/120/01.py index d72d63d..09549ff 100644 --- a/solutions/120/01.py +++ b/solutions/120/01.py @@ -1,5 +1,6 @@ from typing import List + class Solution: def minimumTotal(self, triangle: List[List[int]]) -> int: # Start from the second-to-last row and work upwards @@ -7,6 +8,5 @@ def minimumTotal(self, triangle: List[List[int]]) -> int: for j in range(len(triangle[i])): # Choose the minimum path from the two children below triangle[i][j] += min(triangle[i + 1][j], triangle[i + 1][j + 1]) - - return triangle[0][0] + return triangle[0][0] diff --git a/solutions/121/01.py b/solutions/121/01.py index 6c60ef9..b47f89c 100644 --- a/solutions/121/01.py +++ b/solutions/121/01.py @@ -1,10 +1,11 @@ from typing import List + class Solution: def maxProfit(self, prices: List[int]) -> int: - min_price = float('inf') + min_price = float("inf") max_profit = 0 - + for price in prices: # Update minimum price seen so far min_price = min(min_price, price) @@ -12,5 +13,5 @@ def maxProfit(self, prices: List[int]) -> int: profit = price - min_price # Update maximum profit max_profit = max(max_profit, profit) - + return max_profit diff --git a/solutions/122/01.py b/solutions/122/01.py index 1992e2a..d333815 100644 --- a/solutions/122/01.py +++ b/solutions/122/01.py @@ -11,4 +11,4 @@ def maxProfit(prices: List[int]) -> int: if difference > 0: profit += difference - return profit \ No newline at end of file + return profit diff --git a/solutions/123/01.py b/solutions/123/01.py index d97780e..cef363c 100644 --- a/solutions/123/01.py +++ b/solutions/123/01.py @@ -1,19 +1,19 @@ from typing import List + class Solution: def maxProfit(self, prices: List[int]) -> int: # State machine: buy1, sell1, buy2, sell2 - buy1 = buy2 = float('-inf') + buy1 = buy2 = float("-inf") sell1 = sell2 = 0 - + for price in prices: # First transaction buy1 = max(buy1, -price) # Buy at lowest price sell1 = max(sell1, buy1 + price) # Sell at highest profit - + # Second transaction (using profit from first) buy2 = max(buy2, sell1 - price) # Buy at lowest price after first sell sell2 = max(sell2, buy2 + price) # Sell at highest profit - - return sell2 + return sell2 diff --git a/solutions/124/01.py b/solutions/124/01.py index 7e2bba7..f868e73 100644 --- a/solutions/124/01.py +++ b/solutions/124/01.py @@ -1,5 +1,6 @@ from typing import Optional + # Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): @@ -8,23 +9,22 @@ # self.right = right class Solution: def maxPathSum(self, root: Optional[TreeNode]) -> int: - res = float('-inf') - + res = float("-inf") + def dfs(node): nonlocal res if not node: return 0 - + # Get max path sum from left and right subtrees left_sum = max(0, dfs(node.left)) right_sum = max(0, dfs(node.right)) - + # Update global maximum (path through current node) res = max(res, node.val + left_sum + right_sum) - + # Return max path sum that can be extended upward return node.val + max(left_sum, right_sum) - + dfs(root) return res - diff --git a/solutions/1249/01.py b/solutions/1249/01.py index 171d752..ff7e7f9 100644 --- a/solutions/1249/01.py +++ b/solutions/1249/01.py @@ -3,24 +3,23 @@ def minRemoveToMakeValid(self, s: str) -> str: # First pass: mark indices to remove stack = [] to_remove = set() - + for i, char in enumerate(s): - if char == '(': + if char == "(": stack.append(i) - elif char == ')': + elif char == ")": if stack: stack.pop() else: to_remove.add(i) - + # Add remaining unmatched '(' to remove set to_remove.update(stack) - + # Second pass: build result string res = [] for i, char in enumerate(s): if i not in to_remove: res.append(char) - - return ''.join(res) + return "".join(res) diff --git a/solutions/125/01.py b/solutions/125/01.py index e9f0e88..74bff05 100644 --- a/solutions/125/01.py +++ b/solutions/125/01.py @@ -2,36 +2,36 @@ def isPalindrome(s): """ Check if a string is a palindrome after removing non-alphanumeric characters and converting to lowercase. - + Args: s: str - Input string that may contain various characters - + Returns: bool - True if the cleaned string is a palindrome, False otherwise """ # Initialize two pointers left = 0 right = len(s) - 1 - + # Use two pointers to check palindrome property while left < right: # Skip non-alphanumeric characters from left while left < right and not s[left].isalnum(): left += 1 - + # Skip non-alphanumeric characters from right while left < right and not s[right].isalnum(): right -= 1 - + # If pointers haven't crossed, compare characters if left < right: # Convert to lowercase and compare if s[left].lower() != s[right].lower(): return False - + # Move pointers inward left += 1 right -= 1 - + # If we reach here, all characters matched return True diff --git a/solutions/1261/01.py b/solutions/1261/01.py index 605fe9e..d05a944 100644 --- a/solutions/1261/01.py +++ b/solutions/1261/01.py @@ -8,7 +8,7 @@ class FindElements: def __init__(self, root: Optional[TreeNode]): self.values = set() - + def recover(node, val): if not node: return @@ -16,7 +16,7 @@ def recover(node, val): self.values.add(val) recover(node.left, 2 * val + 1) recover(node.right, 2 * val + 2) - + recover(root, 0) def find(self, target: int) -> bool: diff --git a/solutions/1268/01.py b/solutions/1268/01.py index ba482c1..40c36c1 100644 --- a/solutions/1268/01.py +++ b/solutions/1268/01.py @@ -1,20 +1,21 @@ class Solution: - def suggestedProducts(self, products: List[str], searchWord: str) -> List[List[str]]: + def suggestedProducts( + self, products: List[str], searchWord: str + ) -> List[List[str]]: products.sort() res = [] prefix = "" - + for char in searchWord: prefix += char suggestions = [] - + for product in products: if product.startswith(prefix): suggestions.append(product) if len(suggestions) == 3: break - + res.append(suggestions) - - return res + return res diff --git a/solutions/127/01.py b/solutions/127/01.py index a4f7bf6..3228dbf 100644 --- a/solutions/127/01.py +++ b/solutions/127/01.py @@ -1,33 +1,33 @@ from typing import List from collections import deque + class Solution: def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: word_set = set(wordList) - + if endWord not in word_set: return 0 - + queue = deque([(beginWord, 1)]) visited = {beginWord} - + while queue: word, length = queue.popleft() - + if word == endWord: return length - + # Try changing each character for i in range(len(word)): - for c in 'abcdefghijklmnopqrstuvwxyz': + for c in "abcdefghijklmnopqrstuvwxyz": if c == word[i]: continue - - new_word = word[:i] + c + word[i+1:] - + + new_word = word[:i] + c + word[i + 1 :] + if new_word in word_set and new_word not in visited: visited.add(new_word) queue.append((new_word, length + 1)) - - return 0 + return 0 diff --git a/solutions/128/01.py b/solutions/128/01.py index 4ad0902..b9e85df 100644 --- a/solutions/128/01.py +++ b/solutions/128/01.py @@ -1,24 +1,24 @@ def longestConsecutive(nums): if not nums: return 0 - + # Convert array to hash set for O(1) lookup num_set = set(nums) max_length = 0 - + # For each number, check if it's the start of a consecutive sequence for num in num_set: # A number is a starting point if num - 1 is NOT in the set if num - 1 not in num_set: current_length = 1 current_num = num - + # Expand the sequence by checking consecutive numbers while current_num + 1 in num_set: current_length += 1 current_num += 1 - + # Update maximum length if current sequence is longer max_length = max(max_length, current_length) - + return max_length diff --git a/solutions/1288/01.py b/solutions/1288/01.py index 35632ce..63d9c6c 100644 --- a/solutions/1288/01.py +++ b/solutions/1288/01.py @@ -3,15 +3,14 @@ def removeCoveredIntervals(self, intervals: List[List[int]]) -> int: # Sort by start (ascending), then by end (descending) # This ensures that if two intervals have same start, wider one comes first intervals.sort(key=lambda x: (x[0], -x[1])) - + res = 0 max_end = -1 - + for start, end in intervals: # If current interval is not covered if end > max_end: res += 1 max_end = end - - return res + return res diff --git a/solutions/129/01.py b/solutions/129/01.py index 7eb42ca..9193b74 100644 --- a/solutions/129/01.py +++ b/solutions/129/01.py @@ -1,5 +1,6 @@ from typing import Optional + # Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): @@ -9,24 +10,23 @@ class Solution: def sumNumbers(self, root: Optional[TreeNode]) -> int: res = 0 - + def dfs(node, current_sum): nonlocal res if not node: return - + # Update current number current_sum = current_sum * 10 + node.val - + # If leaf node, add to result if not node.left and not node.right: res += current_sum return - + # Recursively process left and right subtrees dfs(node.left, current_sum) dfs(node.right, current_sum) - + dfs(root, 0) return res - diff --git a/solutions/13/01.py b/solutions/13/01.py index da74973..2b30740 100644 --- a/solutions/13/01.py +++ b/solutions/13/01.py @@ -1,31 +1,22 @@ class Solution: def romanToInt(self, s: str) -> int: # Map of Roman symbols to values - roman_map = { - 'I': 1, - 'V': 5, - 'X': 10, - 'L': 50, - 'C': 100, - 'D': 500, - 'M': 1000 - } - + roman_map = {"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000} + res = 0 prev_value = 0 - + # Process from right to left for i in range(len(s) - 1, -1, -1): current_value = roman_map[s[i]] - + # If current value is less than previous, subtract it # Otherwise, add it if current_value < prev_value: res -= current_value else: res += current_value - + prev_value = current_value - - return res + return res diff --git a/solutions/130/01.py b/solutions/130/01.py index 3259556..ca02d73 100644 --- a/solutions/130/01.py +++ b/solutions/130/01.py @@ -5,35 +5,34 @@ def solve(self, board: List[List[str]]) -> None: """ if not board or not board[0]: return - + m, n = len(board), len(board[0]) - + def dfs(i, j): # Mark 'O' on border and connected to border as 'E' (escape) - if i < 0 or i >= m or j < 0 or j >= n or board[i][j] != 'O': + if i < 0 or i >= m or j < 0 or j >= n or board[i][j] != "O": return - - board[i][j] = 'E' + + board[i][j] = "E" # Check all 4 directions dfs(i + 1, j) dfs(i - 1, j) dfs(i, j + 1) dfs(i, j - 1) - + # Mark all border 'O's and their connections as 'E' for i in range(m): dfs(i, 0) # Left border dfs(i, n - 1) # Right border - + for j in range(n): dfs(0, j) # Top border dfs(m - 1, j) # Bottom border - + # Convert remaining 'O' to 'X' and 'E' back to 'O' for i in range(m): for j in range(n): - if board[i][j] == 'O': - board[i][j] = 'X' - elif board[i][j] == 'E': - board[i][j] = 'O' - + if board[i][j] == "O": + board[i][j] = "X" + elif board[i][j] == "E": + board[i][j] = "O" diff --git a/solutions/1304/01.py b/solutions/1304/01.py index 48b73f5..f5656f6 100644 --- a/solutions/1304/01.py +++ b/solutions/1304/01.py @@ -1,16 +1,15 @@ class Solution: def sumZero(self, n: int) -> List[int]: res = [] - + # For even n: add pairs of positive and negative numbers # For odd n: add pairs plus 0 for i in range(1, n // 2 + 1): res.append(i) res.append(-i) - + # If n is odd, add 0 if n % 2 == 1: res.append(0) - - return res + return res diff --git a/solutions/1318/01.py b/solutions/1318/01.py index e8cfba4..b6a740e 100644 --- a/solutions/1318/01.py +++ b/solutions/1318/01.py @@ -1,21 +1,20 @@ class Solution: def minFlips(self, a: int, b: int, c: int) -> int: res = 0 - + while a > 0 or b > 0 or c > 0: a_bit = a & 1 b_bit = b & 1 c_bit = c & 1 - + if (a_bit | b_bit) != c_bit: if c_bit == 1: res += 1 else: res += a_bit + b_bit - + a >>= 1 b >>= 1 c >>= 1 - - return res + return res diff --git a/solutions/133/01.py b/solutions/133/01.py index a029c4c..ca3e194 100644 --- a/solutions/133/01.py +++ b/solutions/133/01.py @@ -7,28 +7,29 @@ def __init__(self, val = 0, neighbors = None): """ from typing import Optional + + class Solution: - def cloneGraph(self, node: Optional['Node']) -> Optional['Node']: + def cloneGraph(self, node: Optional["Node"]) -> Optional["Node"]: if not node: return None - + # Dictionary to map original nodes to cloned nodes node_map = {} - + def clone(node): # If already cloned, return the clone if node in node_map: return node_map[node] - + # Create a new node clone_node = Node(node.val) node_map[node] = clone_node - + # Clone all neighbors for neighbor in node.neighbors: clone_node.neighbors.append(clone(neighbor)) - + return clone_node - - return clone(node) + return clone(node) diff --git a/solutions/1337/01.py b/solutions/1337/01.py index 62bad3d..8e8a24e 100644 --- a/solutions/1337/01.py +++ b/solutions/1337/01.py @@ -6,11 +6,10 @@ def kWeakestRows(self, mat: List[List[int]], k: int) -> List[int]: # Count soldiers (1s) in the row strength = sum(row) strengths.append((strength, i)) - + # Sort by strength, then by index strengths.sort() - + # Return first k indices res = [idx for _, idx in strengths[:k]] return res - diff --git a/solutions/134/01.py b/solutions/134/01.py index 19377ae..78b5a05 100644 --- a/solutions/134/01.py +++ b/solutions/134/01.py @@ -4,21 +4,20 @@ def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int: total_cost = 0 current_tank = 0 start = 0 - + for i in range(len(gas)): total_gas += gas[i] total_cost += cost[i] current_tank += gas[i] - cost[i] - + # If current_tank < 0, we can't start from any station # in the range [start, i], so try starting from i+1 if current_tank < 0: start = i + 1 current_tank = 0 - + # If total gas < total cost, it's impossible if total_gas < total_cost: return -1 - - return start + return start diff --git a/solutions/1347/01.py b/solutions/1347/01.py index 867ec5e..bcb0551 100644 --- a/solutions/1347/01.py +++ b/solutions/1347/01.py @@ -1,13 +1,13 @@ class Solution: def minSteps(self, s: str, t: str) -> int: from collections import Counter - + count_s = Counter(s) count_t = Counter(t) - + res = 0 for char in count_s: if count_s[char] > count_t[char]: res += count_s[char] - count_t[char] - + return res diff --git a/solutions/135/01.py b/solutions/135/01.py index c72a5c5..db75cf5 100644 --- a/solutions/135/01.py +++ b/solutions/135/01.py @@ -2,16 +2,15 @@ class Solution: def candy(self, ratings: List[int]) -> int: n = len(ratings) res = [1] * n - + # Left to right: if rating[i] > rating[i-1], give more candy for i in range(1, n): if ratings[i] > ratings[i - 1]: res[i] = res[i - 1] + 1 - + # Right to left: if rating[i] > rating[i+1], give more candy for i in range(n - 2, -1, -1): if ratings[i] > ratings[i + 1]: res[i] = max(res[i], res[i + 1] + 1) - - return sum(res) + return sum(res) diff --git a/solutions/136/01.py b/solutions/136/01.py index ddf3955..2a6497a 100644 --- a/solutions/136/01.py +++ b/solutions/136/01.py @@ -1,9 +1,9 @@ from typing import List + class Solution: def singleNumber(self, nums: List[int]) -> int: res = 0 for num in nums: res ^= num return res - diff --git a/solutions/137/01.py b/solutions/137/01.py index 7648df8..4357ec0 100644 --- a/solutions/137/01.py +++ b/solutions/137/01.py @@ -2,12 +2,11 @@ class Solution: def singleNumber(self, nums: List[int]) -> int: ones = 0 # Bits that appear once twos = 0 # Bits that appear twice - + for num in nums: # Update ones: bits that appear once (not in twos) ones = (ones ^ num) & ~twos # Update twos: bits that appear twice (in ones) twos = (twos ^ num) & ~ones - - return ones + return ones diff --git a/solutions/1372/01.py b/solutions/1372/01.py index 7f3aab3..e48ce2b 100644 --- a/solutions/1372/01.py +++ b/solutions/1372/01.py @@ -5,17 +5,18 @@ # self.left = left # self.right = right + class Solution: def longestZigZag(self, root) -> int: res = 0 - + def dfs(node, is_left, length): nonlocal res if not node: return - + res = max(res, length) - + if is_left: # Coming from left, go right dfs(node.right, False, length + 1) @@ -26,10 +27,9 @@ def dfs(node, is_left, length): dfs(node.left, True, length + 1) # Or start new path going right dfs(node.right, False, 1) - + if root: dfs(root.left, True, 1) dfs(root.right, False, 1) - - return res + return res diff --git a/solutions/138/01.py b/solutions/138/01.py index 7f18992..1b27a2c 100644 --- a/solutions/138/01.py +++ b/solutions/138/01.py @@ -7,19 +7,20 @@ def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None): self.random = random """ + class Solution: - def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]': + def copyRandomList(self, head: "Optional[Node]") -> "Optional[Node]": if not head: return None - + # First pass: create new nodes and map old to new node_map = {} curr = head - + while curr: node_map[curr] = Node(curr.val) curr = curr.next - + # Second pass: set next and random pointers curr = head while curr: @@ -28,6 +29,5 @@ def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]': if curr.random: node_map[curr].random = node_map[curr.random] curr = curr.next - - return node_map[head] + return node_map[head] diff --git a/solutions/139/01.py b/solutions/139/01.py index 3cb6ec8..86f5d51 100644 --- a/solutions/139/01.py +++ b/solutions/139/01.py @@ -1,20 +1,20 @@ from typing import List + class Solution: def wordBreak(self, s: str, wordDict: List[str]) -> bool: word_set = set(wordDict) n = len(s) - + # dp[i] represents if s[0:i] can be segmented dp = [False] * (n + 1) dp[0] = True # Empty string can always be segmented - + for i in range(1, n + 1): for j in range(i): # If s[0:j] can be segmented and s[j:i] is in wordDict if dp[j] and s[j:i] in word_set: dp[i] = True break - - return dp[n] + return dp[n] diff --git a/solutions/142/01.py b/solutions/142/01.py index 07c4f67..97b78c2 100644 --- a/solutions/142/01.py +++ b/solutions/142/01.py @@ -4,12 +4,13 @@ # self.val = x # self.next = None + class Solution: def detectCycle(self, head): # Floyd's cycle detection algorithm slow = head fast = head - + # Find meeting point while fast and fast.next: slow = slow.next @@ -21,5 +22,5 @@ def detectCycle(self, head): slow = slow.next fast = fast.next return slow - + return None diff --git a/solutions/1423/01.py b/solutions/1423/01.py index e2aa77a..7e175df 100644 --- a/solutions/1423/01.py +++ b/solutions/1423/01.py @@ -1,22 +1,21 @@ class Solution: def maxScore(self, cardPoints: List[int], k: int) -> int: n = len(cardPoints) - + # Sliding window approach: find minimum sum of subarray of length (n - k) # Then answer is total_sum - min_subarray_sum - + window_size = n - k window_sum = sum(cardPoints[:window_size]) min_sum = window_sum - + # Slide the window for i in range(window_size, n): window_sum = window_sum - cardPoints[i - window_size] + cardPoints[i] min_sum = min(min_sum, window_sum) - + # Total sum minus minimum window sum total_sum = sum(cardPoints) res = total_sum - min_sum - - return res + return res diff --git a/solutions/1431/01.py b/solutions/1431/01.py index c7b219e..4710c9a 100644 --- a/solutions/1431/01.py +++ b/solutions/1431/01.py @@ -2,14 +2,14 @@ class Solution: def kidsWithCandies(self, candies: List[int], extraCandies: int) -> List[bool]: # Find the maximum number of candies max_candies = max(candies) - + res = [] - + # For each kid, check if adding extraCandies makes them have the most for candy_count in candies: if candy_count + extraCandies >= max_candies: res.append(True) else: res.append(False) - + return res diff --git a/solutions/1448/01.py b/solutions/1448/01.py index f879434..0ec8512 100644 --- a/solutions/1448/01.py +++ b/solutions/1448/01.py @@ -7,19 +7,18 @@ class Solution: def goodNodes(self, root: TreeNode) -> int: res = 0 - + def dfs(node, max_val): nonlocal res if not node: return - + if node.val >= max_val: res += 1 max_val = node.val - + dfs(node.left, max_val) dfs(node.right, max_val) - + dfs(root, root.val) return res - diff --git a/solutions/1456/01.py b/solutions/1456/01.py index 3d8612f..bf28f98 100644 --- a/solutions/1456/01.py +++ b/solutions/1456/01.py @@ -1,12 +1,12 @@ def maxVowels(s: str, k: int) -> int: - vowels = {'a', 'e', 'i', 'o', 'u'} + vowels = {"a", "e", "i", "o", "u"} current_vowel_count = 0 # 1. Calculate the vowel count for the initial window (first k characters) for i in range(k): if s[i] in vowels: current_vowel_count += 1 - + max_vowel_count = current_vowel_count # 2. Slide the window across the rest of the string @@ -16,13 +16,13 @@ def maxVowels(s: str, k: int) -> int: # The character leaving is at index (i - k) if s[i - k] in vowels: current_vowel_count -= 1 - + # Add the contribution of the new character entering the window # The new character entering is at index (i) if s[i] in vowels: current_vowel_count += 1 - + max_vowel_count = max(max_vowel_count, current_vowel_count) - + res = max_vowel_count - return res \ No newline at end of file + return res diff --git a/solutions/1466/01.py b/solutions/1466/01.py index 7bf97b2..21de1e7 100644 --- a/solutions/1466/01.py +++ b/solutions/1466/01.py @@ -1,13 +1,13 @@ class Solution: def minReorder(self, n: int, connections: List[List[int]]) -> int: graph = [[] for _ in range(n)] - + for a, b in connections: graph[a].append((b, 1)) graph[b].append((a, 0)) - + res = 0 - + def dfs(node, parent): nonlocal res for neighbor, direction in graph[node]: @@ -16,7 +16,6 @@ def dfs(node, parent): if direction == 1: res += 1 dfs(neighbor, node) - + dfs(0, -1) return res - diff --git a/solutions/1480/01.py b/solutions/1480/01.py index 2a048ad..9f54111 100644 --- a/solutions/1480/01.py +++ b/solutions/1480/01.py @@ -1,13 +1,13 @@ from typing import List + class Solution: def runningSum(self, nums: List[int]) -> List[int]: res = [] current_sum = 0 - + for num in nums: current_sum += num res.append(current_sum) - - return res + return res diff --git a/solutions/149/01.py b/solutions/149/01.py index cc06c27..410de95 100644 --- a/solutions/149/01.py +++ b/solutions/149/01.py @@ -2,46 +2,45 @@ class Solution: def maxPoints(self, points: List[List[int]]) -> int: if len(points) <= 2: return len(points) - + res = 0 - + for i in range(len(points)): slope_count = {} same_point = 1 - + for j in range(i + 1, len(points)): x1, y1 = points[i] x2, y2 = points[j] - + # Same point if x1 == x2 and y1 == y2: same_point += 1 continue - + # Calculate slope dx = x2 - x1 dy = y2 - y1 - + # Reduce to simplest form using GCD g = self.gcd(dx, dy) if g != 0: dx //= g dy //= g - + slope = (dx, dy) slope_count[slope] = slope_count.get(slope, 0) + 1 - + # Find max points on same line max_points = same_point if slope_count: max_points += max(slope_count.values()) - + res = max(res, max_points) - + return res - + def gcd(self, a, b): while b: a, b = b, a % b return abs(a) - diff --git a/solutions/1493/01.py b/solutions/1493/01.py index f9a882b..99435df 100644 --- a/solutions/1493/01.py +++ b/solutions/1493/01.py @@ -1,24 +1,24 @@ from typing import List + class Solution: def longestSubarray(self, nums: List[int]) -> int: left = 0 max_length = 0 zero_count = 0 - + for right in range(len(nums)): # Expand window if nums[right] == 0: zero_count += 1 - + # Shrink window if we have more than one zero while zero_count > 1: if nums[left] == 0: zero_count -= 1 left += 1 - + # Update maximum length (subtract 1 because we must delete one element) max_length = max(max_length, right - left) - - return max_length + return max_length diff --git a/solutions/15/01.py b/solutions/15/01.py index 358aba8..a11b30e 100644 --- a/solutions/15/01.py +++ b/solutions/15/01.py @@ -1,37 +1,38 @@ from typing import List + class Solution: def threeSum(self, nums: List[int]) -> List[List[int]]: nums.sort() res = [] n = len(nums) - + for i in range(n - 2): # Skip duplicates for the first number if i > 0 and nums[i] == nums[i - 1]: continue - + left = i + 1 right = n - 1 - + while left < right: current_sum = nums[i] + nums[left] + nums[right] - + if current_sum == 0: res.append([nums[i], nums[left], nums[right]]) - + # Skip duplicates for left while left < right and nums[left] == nums[left + 1]: left += 1 # Skip duplicates for right while left < right and nums[right] == nums[right - 1]: right -= 1 - + left += 1 right -= 1 elif current_sum < 0: left += 1 else: right -= 1 - + return res diff --git a/solutions/150/01.py b/solutions/150/01.py index 138b2ee..d8b7157 100644 --- a/solutions/150/01.py +++ b/solutions/150/01.py @@ -1,27 +1,26 @@ class Solution: def evalRPN(self, tokens: List[str]) -> int: stack = [] - + for token in tokens: - if token in ['+', '-', '*', '/']: + if token in ["+", "-", "*", "/"]: # Pop two operands b = stack.pop() a = stack.pop() - + # Perform operation - if token == '+': + if token == "+": res = a + b - elif token == '-': + elif token == "-": res = a - b - elif token == '*': + elif token == "*": res = a * b else: # token == '/' res = int(a / b) # Truncate towards zero - + stack.append(res) else: # It's a number stack.append(int(token)) - - return stack[0] + return stack[0] diff --git a/solutions/151/01.py b/solutions/151/01.py index ce84b99..1704de2 100644 --- a/solutions/151/01.py +++ b/solutions/151/01.py @@ -3,4 +3,4 @@ def reverseWords(self, s: str) -> str: # Split by spaces and filter out empty strings words = s.split() # Reverse the list and join with spaces - return ' '.join(reversed(words)) + return " ".join(reversed(words)) diff --git a/solutions/1515/01.py b/solutions/1515/01.py index 44840be..f5d8d79 100644 --- a/solutions/1515/01.py +++ b/solutions/1515/01.py @@ -1,35 +1,35 @@ def findMinFibonacciNumbers(k): """ Find the minimum number of Fibonacci numbers whose sum equals k. - + Args: k: int - Target sum to achieve - + Returns: int - Minimum number of Fibonacci numbers needed """ # Generate Fibonacci numbers up to k fib_numbers = [1, 1] - + # Keep generating Fibonacci numbers until we exceed k while fib_numbers[-1] <= k: next_fib = fib_numbers[-1] + fib_numbers[-2] if next_fib > k: break fib_numbers.append(next_fib) - + # Use greedy approach: always choose largest possible Fibonacci number count = 0 remaining = k - + # Start from the largest Fibonacci number and work backwards for i in range(len(fib_numbers) - 1, -1, -1): if fib_numbers[i] <= remaining: remaining -= fib_numbers[i] count += 1 - + # If we've reached the target, we're done if remaining == 0: break - + return count diff --git a/solutions/152/01.py b/solutions/152/01.py index dc1b5d2..d17c1db 100644 --- a/solutions/152/01.py +++ b/solutions/152/01.py @@ -15,4 +15,4 @@ def maxProduct(nums: List[int]) -> int: max_product = max(max_product, curr_max) - return max_product \ No newline at end of file + return max_product diff --git a/solutions/1523/01.py b/solutions/1523/01.py index d5c30b0..0c1f5f5 100644 --- a/solutions/1523/01.py +++ b/solutions/1523/01.py @@ -2,12 +2,11 @@ class Solution: def countOdds(self, low: int, high: int) -> int: # Count of numbers in range [low, high] total = high - low + 1 - + # If total is even, exactly half are odd if total % 2 == 0: return total // 2 - + # If total is odd, check if low is odd # If low is odd, we have one more odd than even return total // 2 + (1 if low % 2 == 1 else 0) - diff --git a/solutions/1528/01.py b/solutions/1528/01.py index e9bdc43..49f7b50 100644 --- a/solutions/1528/01.py +++ b/solutions/1528/01.py @@ -1,11 +1,10 @@ class Solution: def restoreString(self, s: str, indices: List[int]) -> str: # Create result array of same length - res = [''] * len(s) - + res = [""] * len(s) + # Place each character at its correct index for i, char in enumerate(s): res[indices[i]] = char - - return ''.join(res) + return "".join(res) diff --git a/solutions/153/01.py b/solutions/153/01.py index 66695fc..42fab27 100644 --- a/solutions/153/01.py +++ b/solutions/153/01.py @@ -1,19 +1,19 @@ from typing import List + class Solution: def findMin(self, nums: List[int]) -> int: left = 0 right = len(nums) - 1 - + while left < right: mid = (left + right) // 2 - + # If right half is sorted, minimum is in left half if nums[mid] < nums[right]: right = mid # Otherwise, minimum is in right half else: left = mid + 1 - - return nums[left] + return nums[left] diff --git a/solutions/155/01.py b/solutions/155/01.py index b5a6850..9753f02 100644 --- a/solutions/155/01.py +++ b/solutions/155/01.py @@ -29,4 +29,3 @@ def getMin(self) -> int: # obj.pop() # param_3 = obj.top() # param_4 = obj.getMin() - diff --git a/solutions/1551/01.py b/solutions/1551/01.py index daa7612..3b6a94d 100644 --- a/solutions/1551/01.py +++ b/solutions/1551/01.py @@ -2,7 +2,7 @@ class Solution: def minOperations(self, n: int) -> int: # Target value is the average target = n - + # Calculate operations needed res = 0 for i in range(n): @@ -11,5 +11,5 @@ def minOperations(self, n: int) -> int: res += target - current else: break - + return res diff --git a/solutions/1557/01.py b/solutions/1557/01.py index 2da33d8..3a427e6 100644 --- a/solutions/1557/01.py +++ b/solutions/1557/01.py @@ -1,18 +1,18 @@ from typing import List + class Solution: def findSmallestSetOfVertices(self, n: int, edges: List[List[int]]) -> List[int]: # Find all nodes that have no incoming edges has_incoming = [False] * n - + for from_node, to_node in edges: has_incoming[to_node] = True - + # Return all nodes without incoming edges res = [] for i in range(n): if not has_incoming[i]: res.append(i) - - return res + return res diff --git a/solutions/156/01.py b/solutions/156/01.py index 215cf9b..14e6a7b 100644 --- a/solutions/156/01.py +++ b/solutions/156/01.py @@ -7,17 +7,17 @@ # self.left = left # self.right = right + class Solution: def upsideDownBinaryTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]: if not root or not root.left: return root - + new_root = self.upsideDownBinaryTree(root.left) - + root.left.left = root.right root.left.right = root root.left = None root.right = None - - return new_root + return new_root diff --git a/solutions/157/01.py b/solutions/157/01.py index 2f38a8e..2df60d9 100644 --- a/solutions/157/01.py +++ b/solutions/157/01.py @@ -3,19 +3,19 @@ # The read4 API is already defined for you. # def read4(buf4: List[str]) -> int: + class Solution: def read(self, buf: List[str], n: int) -> int: - buf4 = [''] * 4 + buf4 = [""] * 4 total = 0 - + while total < n: count = read4(buf4) if count == 0: break - + copy_count = min(count, n - total) - buf[total:total + copy_count] = buf4[:copy_count] + buf[total : total + copy_count] = buf4[:copy_count] total += copy_count - - return total + return total diff --git a/solutions/158/01.py b/solutions/158/01.py index 1349fd2..28f7708 100644 --- a/solutions/158/01.py +++ b/solutions/158/01.py @@ -3,23 +3,23 @@ # The read4 API is already defined for you. # def read4(buf4: List[str]) -> int: + class Solution: def __init__(self): self.queue = [] - + def read(self, buf: List[str], n: int) -> int: idx = 0 - + while idx < n: if self.queue: buf[idx] = self.queue.pop(0) idx += 1 else: - buf4 = [''] * 4 + buf4 = [""] * 4 count = read4(buf4) if count == 0: break self.queue.extend(buf4[:count]) - - return idx + return idx diff --git a/solutions/1584/01.py b/solutions/1584/01.py index 3a54d5a..72b5aec 100644 --- a/solutions/1584/01.py +++ b/solutions/1584/01.py @@ -1,32 +1,33 @@ class Solution: def minCostConnectPoints(self, points: List[List[int]]) -> int: import heapq - + n = len(points) if n == 1: return 0 - + # Prim's algorithm using min heap # Start with point 0 visited = set() heap = [(0, 0)] # (cost, point_index) res = 0 - + while len(visited) < n: cost, curr = heapq.heappop(heap) - + if curr in visited: continue - + visited.add(curr) res += cost - + # Add all unvisited neighbors to heap for i in range(n): if i not in visited: # Calculate Manhattan distance - dist = abs(points[curr][0] - points[i][0]) + abs(points[curr][1] - points[i][1]) + dist = abs(points[curr][0] - points[i][0]) + abs( + points[curr][1] - points[i][1] + ) heapq.heappush(heap, (dist, i)) - - return res + return res diff --git a/solutions/159/01.py b/solutions/159/01.py index dff52f6..f909268 100644 --- a/solutions/159/01.py +++ b/solutions/159/01.py @@ -1,23 +1,23 @@ from collections import defaultdict + class Solution: def lengthOfLongestSubstringTwoDistinct(self, s: str) -> int: left = 0 right = 0 res = 0 char_count = defaultdict(int) - + while right < len(s): char_count[s[right]] += 1 - + while len(char_count) > 2: char_count[s[left]] -= 1 if char_count[s[left]] == 0: del char_count[s[left]] left += 1 - + res = max(res, right - left + 1) right += 1 - - return res + return res diff --git a/solutions/160/01.py b/solutions/160/01.py index 947b8ce..5e965a9 100644 --- a/solutions/160/01.py +++ b/solutions/160/01.py @@ -4,20 +4,22 @@ # self.val = x # self.next = None + class Solution: - def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]: + def getIntersectionNode( + self, headA: ListNode, headB: ListNode + ) -> Optional[ListNode]: # Two pointer approach: traverse both lists # When one pointer reaches end, switch to other list # This way both pointers will meet at intersection (if exists) # or both will be None (if no intersection) - + p1, p2 = headA, headB - + while p1 != p2: # If p1 reaches end, switch to headB p1 = p1.next if p1 else headB # If p2 reaches end, switch to headA p2 = p2.next if p2 else headA - - return p1 + return p1 diff --git a/solutions/1605/01.py b/solutions/1605/01.py index f7ad8d3..d1632ad 100644 --- a/solutions/1605/01.py +++ b/solutions/1605/01.py @@ -2,12 +2,12 @@ class Solution: def restoreMatrix(self, rowSum: List[int], colSum: List[int]) -> List[List[int]]: m, n = len(rowSum), len(colSum) res = [[0] * n for _ in range(m)] - + for i in range(m): for j in range(n): val = min(rowSum[i], colSum[j]) res[i][j] = val rowSum[i] -= val colSum[j] -= val - + return res diff --git a/solutions/161/01.py b/solutions/161/01.py index 7dc1cc9..899e4ba 100644 --- a/solutions/161/01.py +++ b/solutions/161/01.py @@ -1,20 +1,19 @@ class Solution: def isOneEditDistance(self, s: str, t: str) -> bool: len_s, len_t = len(s), len(t) - + if abs(len_s - len_t) > 1: return False - + if len_s > len_t: s, t = t, s len_s, len_t = len_t, len_s - + for i in range(len_s): if s[i] != t[i]: if len_s == len_t: - return s[i+1:] == t[i+1:] + return s[i + 1 :] == t[i + 1 :] else: - return s[i:] == t[i+1:] - - return len_s + 1 == len_t + return s[i:] == t[i + 1 :] + return len_s + 1 == len_t diff --git a/solutions/162/01.py b/solutions/162/01.py index eb57acb..cbb2dc1 100644 --- a/solutions/162/01.py +++ b/solutions/162/01.py @@ -1,16 +1,15 @@ class Solution: def findPeakElement(self, nums: List[int]) -> int: left, right = 0, len(nums) - 1 - + while left < right: mid = (left + right) // 2 - + # If mid is greater than its right neighbor, peak is in left half if nums[mid] > nums[mid + 1]: right = mid else: # Otherwise, peak is in right half left = mid + 1 - - return left + return left diff --git a/solutions/163/01.py b/solutions/163/01.py index c151b30..a9b0158 100644 --- a/solutions/163/01.py +++ b/solutions/163/01.py @@ -1,16 +1,16 @@ from typing import List + class Solution: def findMissingRanges(self, nums: List[int], lower: int, upper: int) -> List[str]: res = [] prev = lower - 1 - + for num in nums + [upper + 1]: if num - prev == 2: res.append(str(prev + 1)) elif num - prev > 2: res.append(f"{prev + 1}->{num - 1}") prev = num - - return res + return res diff --git a/solutions/1630/01.py b/solutions/1630/01.py index cc6b8b3..5424a12 100644 --- a/solutions/1630/01.py +++ b/solutions/1630/01.py @@ -1,23 +1,25 @@ class Solution: - def checkArithmeticSubarrays(self, nums: List[int], l: List[int], r: List[int]) -> List[bool]: + def checkArithmeticSubarrays( + self, nums: List[int], l: List[int], r: List[int] + ) -> List[bool]: res = [] - + for i in range(len(l)): - subarray = nums[l[i]:r[i] + 1] + subarray = nums[l[i] : r[i] + 1] subarray.sort() - + if len(subarray) < 2: res.append(True) continue - + diff = subarray[1] - subarray[0] is_arithmetic = True - + for j in range(2, len(subarray)): if subarray[j] - subarray[j - 1] != diff: is_arithmetic = False break - + res.append(is_arithmetic) - + return res diff --git a/solutions/167/01.py b/solutions/167/01.py index cb8d019..1114e29 100644 --- a/solutions/167/01.py +++ b/solutions/167/01.py @@ -1,18 +1,19 @@ from typing import List + class Solution: def twoSum(self, numbers: List[int], target: int) -> List[int]: left = 0 right = len(numbers) - 1 - + while left < right: current_sum = numbers[left] + numbers[right] - + if current_sum == target: return [left + 1, right + 1] # 1-indexed elif current_sum < target: left += 1 else: right -= 1 - + return [] diff --git a/solutions/1672/01.py b/solutions/1672/01.py index 026ab70..ffa97e5 100644 --- a/solutions/1672/01.py +++ b/solutions/1672/01.py @@ -1,11 +1,10 @@ class Solution: def maximumWealth(self, accounts: List[List[int]]) -> int: res = 0 - + # Calculate wealth for each customer (sum of all accounts) for customer in accounts: wealth = sum(customer) res = max(res, wealth) - - return res + return res diff --git a/solutions/1679/01.py b/solutions/1679/01.py index c280a30..a2faed8 100644 --- a/solutions/1679/01.py +++ b/solutions/1679/01.py @@ -1,13 +1,13 @@ class Solution: def maxOperations(self, nums: List[int], k: int) -> int: from collections import Counter - + count = Counter(nums) res = 0 - + for num in list(count.keys()): complement = k - num - + if complement in count: if num == complement: # Same number, can pair with itself @@ -20,6 +20,5 @@ def maxOperations(self, nums: List[int], k: int) -> int: res += pairs count[num] -= pairs count[complement] -= pairs - - return res + return res diff --git a/solutions/169/01.py b/solutions/169/01.py index c8abc31..4a069c9 100644 --- a/solutions/169/01.py +++ b/solutions/169/01.py @@ -13,4 +13,4 @@ def majorityElement(nums: List[int]) -> int: candidate = nums[i] count = 1 - return candidate \ No newline at end of file + return candidate diff --git a/solutions/17/01.py b/solutions/17/01.py index 602b9bb..14e7f34 100644 --- a/solutions/17/01.py +++ b/solutions/17/01.py @@ -1,38 +1,38 @@ from typing import List + class Solution: def letterCombinations(self, digits: str) -> List[str]: if not digits: return [] - + # Mapping of digits to letters digit_to_letters = { - '2': 'abc', - '3': 'def', - '4': 'ghi', - '5': 'jkl', - '6': 'mno', - '7': 'pqrs', - '8': 'tuv', - '9': 'wxyz' + "2": "abc", + "3": "def", + "4": "ghi", + "5": "jkl", + "6": "mno", + "7": "pqrs", + "8": "tuv", + "9": "wxyz", } - + res = [] - + def backtrack(index, current_combination): # Base case: if we've processed all digits if index == len(digits): res.append(current_combination) return - + # Get letters for current digit current_digit = digits[index] letters = digit_to_letters[current_digit] - + # Try each letter for current digit for letter in letters: backtrack(index + 1, current_combination + letter) - + backtrack(0, "") return res - diff --git a/solutions/170/01.py b/solutions/170/01.py index 30982d7..cd0744e 100644 --- a/solutions/170/01.py +++ b/solutions/170/01.py @@ -1,12 +1,13 @@ from collections import defaultdict + class TwoSum: def __init__(self): self.num_counts = defaultdict(int) - + def add(self, number: int) -> None: self.num_counts[number] += 1 - + def find(self, value: int) -> bool: for num in self.num_counts: complement = value - num @@ -14,4 +15,3 @@ def find(self, value: int) -> bool: if complement != num or self.num_counts[num] > 1: return True return False - diff --git a/solutions/1704/01.py b/solutions/1704/01.py index 4b758ad..0b43e03 100644 --- a/solutions/1704/01.py +++ b/solutions/1704/01.py @@ -1,21 +1,20 @@ class Solution: def halvesAreAlike(self, s: str) -> bool: - vowels = set('aeiouAEIOU') + vowels = set("aeiouAEIOU") n = len(s) mid = n // 2 - + count_first = 0 count_second = 0 - + # Count vowels in first half for i in range(mid): if s[i] in vowels: count_first += 1 - + # Count vowels in second half for i in range(mid, n): if s[i] in vowels: count_second += 1 - - return count_first == count_second + return count_first == count_second diff --git a/solutions/172/01.py b/solutions/172/01.py index fe772bc..5c98941 100644 --- a/solutions/172/01.py +++ b/solutions/172/01.py @@ -1,12 +1,11 @@ class Solution: def trailingZeroes(self, n: int) -> int: res = 0 - + # Count factors of 5 (each 5 contributes to a trailing zero) # We need to count 5, 25, 125, etc. while n > 0: n //= 5 res += n - - return res + return res diff --git a/solutions/173/01.py b/solutions/173/01.py index 80022ef..ddbc2cc 100644 --- a/solutions/173/01.py +++ b/solutions/173/01.py @@ -32,4 +32,3 @@ def hasNext(self) -> bool: # obj = BSTIterator(root) # param_1 = obj.next() # param_2 = obj.hasNext() - diff --git a/solutions/1732/01.py b/solutions/1732/01.py index 4f3473f..9be5aba 100644 --- a/solutions/1732/01.py +++ b/solutions/1732/01.py @@ -1,12 +1,13 @@ from typing import List + class Solution: def largestAltitude(self, gain: List[int]) -> int: current_altitude = 0 max_altitude = 0 - + for g in gain: current_altitude += g max_altitude = max(max_altitude, current_altitude) - + return max_altitude diff --git a/solutions/1769/01.py b/solutions/1769/01.py index 7ed4820..feeb22b 100644 --- a/solutions/1769/01.py +++ b/solutions/1769/01.py @@ -1,17 +1,17 @@ from typing import List + class Solution: def minOperations(self, boxes: str) -> List[int]: n = len(boxes) res = [0] * n - + # For each position, calculate operations needed for i in range(n): operations = 0 for j in range(n): - if boxes[j] == '1': + if boxes[j] == "1": operations += abs(i - j) res[i] = operations - - return res + return res diff --git a/solutions/1798/01.py b/solutions/1798/01.py index e4401d7..bd1b721 100644 --- a/solutions/1798/01.py +++ b/solutions/1798/01.py @@ -4,4 +4,4 @@ def getMaximumConsecutive(coins): if coin > res: break res += coin - return res \ No newline at end of file + return res diff --git a/solutions/1828/01.py b/solutions/1828/01.py index 890c896..f7b4451 100644 --- a/solutions/1828/01.py +++ b/solutions/1828/01.py @@ -1,24 +1,26 @@ from typing import List + class Solution: - def countPoints(self, points: List[List[int]], queries: List[List[int]]) -> List[int]: + def countPoints( + self, points: List[List[int]], queries: List[List[int]] + ) -> List[int]: res = [] - + for query in queries: x, y, r = query count = 0 - + # Check each point for point in points: px, py = point # Calculate distance from point to circle center distance_squared = (px - x) ** 2 + (py - y) ** 2 - + # Point is inside if distance <= radius if distance_squared <= r * r: count += 1 - + res.append(count) - - return res + return res diff --git a/solutions/188/01.py b/solutions/188/01.py index 618ba9b..bc6b662 100644 --- a/solutions/188/01.py +++ b/solutions/188/01.py @@ -2,9 +2,9 @@ class Solution: def maxProfit(self, k: int, prices: List[int]) -> int: if not prices or k == 0: return 0 - + n = len(prices) - + # If k >= n/2, we can make as many transactions as we want # This becomes the "unlimited transactions" problem if k >= n // 2: @@ -13,12 +13,12 @@ def maxProfit(self, k: int, prices: List[int]) -> int: if prices[i] > prices[i - 1]: res += prices[i] - prices[i - 1] return res - + # DP: buy[i][j] = max profit with at most i transactions, holding stock after j-th day # sell[i][j] = max profit with at most i transactions, not holding stock after j-th day - buy = [-float('inf')] * (k + 1) + buy = [-float("inf")] * (k + 1) sell = [0] * (k + 1) - + for price in prices: # Update for each transaction count from k down to 1 for i in range(k, 0, -1): @@ -26,6 +26,5 @@ def maxProfit(self, k: int, prices: List[int]) -> int: buy[i] = max(buy[i], sell[i - 1] - price) # Either keep not holding or sell today sell[i] = max(sell[i], buy[i] + price) - - return sell[k] + return sell[k] diff --git a/solutions/19/01.py b/solutions/19/01.py index 1c627c7..49bc14f 100644 --- a/solutions/19/01.py +++ b/solutions/19/01.py @@ -4,27 +4,27 @@ # self.val = val # self.next = next + class Solution: def removeNthFromEnd(self, head, n: int): # Create a dummy node to handle edge cases dummy = ListNode(0) dummy.next = head - + # Two pointers: fast and slow fast = dummy slow = dummy - + # Move fast pointer n+1 steps ahead for _ in range(n + 1): fast = fast.next - + # Move both pointers until fast reaches the end while fast: fast = fast.next slow = slow.next - + # Remove the nth node from end slow.next = slow.next.next - - return dummy.next + return dummy.next diff --git a/solutions/190/01.py b/solutions/190/01.py index 3df3a1e..1796a71 100644 --- a/solutions/190/01.py +++ b/solutions/190/01.py @@ -5,6 +5,5 @@ def reverseBits(self, n: int) -> int: # Extract the i-th bit from n bit = (n >> i) & 1 # Place it at position (31 - i) in the result - res |= (bit << (31 - i)) + res |= bit << (31 - i) return res - diff --git a/solutions/191/01.py b/solutions/191/01.py index 2e07362..548a6ad 100644 --- a/solutions/191/01.py +++ b/solutions/191/01.py @@ -6,4 +6,3 @@ def hammingWeight(self, n: int) -> int: n &= n - 1 res += 1 return res - diff --git a/solutions/1920/01.py b/solutions/1920/01.py index f232437..2c43a28 100644 --- a/solutions/1920/01.py +++ b/solutions/1920/01.py @@ -4,4 +4,3 @@ def buildArray(self, nums: List[int]) -> List[int]: for i in range(len(nums)): res.append(nums[nums[i]]) return res - diff --git a/solutions/1926/01.py b/solutions/1926/01.py index 250e210..37c731e 100644 --- a/solutions/1926/01.py +++ b/solutions/1926/01.py @@ -1,31 +1,34 @@ from typing import List from collections import deque + class Solution: def nearestExit(self, maze: List[List[str]], entrance: List[int]) -> int: m, n = len(maze), len(maze[0]) directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] - + queue = deque([(entrance[0], entrance[1], 0)]) visited = {(entrance[0], entrance[1])} - + while queue: row, col, steps = queue.popleft() - + # Check if we're at an exit (boundary and not entrance) - if (row == 0 or row == m - 1 or col == 0 or col == n - 1): + if row == 0 or row == m - 1 or col == 0 or col == n - 1: if [row, col] != entrance: return steps - + # Explore neighbors for dr, dc in directions: new_row, new_col = row + dr, col + dc - - if (0 <= new_row < m and 0 <= new_col < n and - maze[new_row][new_col] == '.' and - (new_row, new_col) not in visited): + + if ( + 0 <= new_row < m + and 0 <= new_col < n + and maze[new_row][new_col] == "." + and (new_row, new_col) not in visited + ): visited.add((new_row, new_col)) queue.append((new_row, new_col, steps + 1)) - - return -1 + return -1 diff --git a/solutions/1929/01.py b/solutions/1929/01.py index d0c0c9c..0125ba1 100644 --- a/solutions/1929/01.py +++ b/solutions/1929/01.py @@ -2,4 +2,3 @@ class Solution: def getConcatenation(self, nums: List[int]) -> List[int]: res = nums + nums return res - diff --git a/solutions/1963/01.py b/solutions/1963/01.py index c4aa044..6074932 100644 --- a/solutions/1963/01.py +++ b/solutions/1963/01.py @@ -1,11 +1,11 @@ def getXORSum(arr1, arr2): """ Find the XOR sum of all pairs bitwise AND results. - + Args: arr1: List[int] - First array of integers arr2: List[int] - Second array of integers - + Returns: int - XOR sum of all (arr1[i] AND arr2[j]) pairs """ @@ -13,11 +13,11 @@ def getXORSum(arr1, arr2): arr2_xor_sum = 0 for num in arr2: arr2_xor_sum ^= num - + # For each element in arr1, compute (element AND arr2_xor_sum) # Then XOR all these results together result = 0 for num in arr1: - result ^= (num & arr2_xor_sum) - + result ^= num & arr2_xor_sum + return result diff --git a/solutions/198/01.py b/solutions/198/01.py index ecf026d..54be079 100644 --- a/solutions/198/01.py +++ b/solutions/198/01.py @@ -1,9 +1,10 @@ from typing import List + class Solution: def rob(self, nums: List[int]) -> int: n = len(nums) - + # Base cases if n == 0: return 0 @@ -11,16 +12,15 @@ def rob(self, nums: List[int]) -> int: return nums[0] if n == 2: return max(nums[0], nums[1]) - + # dp[i] represents maximum money robbed up to house i dp = [0] * n dp[0] = nums[0] dp[1] = max(nums[0], nums[1]) - + # Fill dp array for i in range(2, n): # Either rob current house + best from i-2, or skip current house dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) - - return dp[n - 1] + return dp[n - 1] diff --git a/solutions/199/01.py b/solutions/199/01.py index 02c6df8..60b7fc3 100644 --- a/solutions/199/01.py +++ b/solutions/199/01.py @@ -8,28 +8,28 @@ from typing import List from collections import deque + class Solution: def rightSideView(self, root) -> List[int]: if not root: return [] - + res = [] queue = deque([root]) - + while queue: level_size = len(queue) - + for i in range(level_size): node = queue.popleft() - + # Add the rightmost node of each level if i == level_size - 1: res.append(node.val) - + if node.left: queue.append(node.left) if node.right: queue.append(node.right) - - return res + return res diff --git a/solutions/20/01.py b/solutions/20/01.py index 5c07293..6a7f1f9 100644 --- a/solutions/20/01.py +++ b/solutions/20/01.py @@ -1,8 +1,8 @@ class Solution: def isValid(self, s: str) -> bool: stack = [] - mapping = {')': '(', '}': '{', ']': '['} - + mapping = {")": "(", "}": "{", "]": "["} + for char in s: if char in mapping: # Closing bracket @@ -11,6 +11,5 @@ def isValid(self, s: str) -> bool: else: # Opening bracket stack.append(char) - - return len(stack) == 0 + return len(stack) == 0 diff --git a/solutions/200/01.py b/solutions/200/01.py index 80e752b..a89f0af 100644 --- a/solutions/200/01.py +++ b/solutions/200/01.py @@ -1,33 +1,33 @@ from typing import List + class Solution: def numIslands(self, grid: List[List[str]]) -> int: if not grid: return 0 - + m, n = len(grid), len(grid[0]) res = 0 - + def dfs(i, j): # Check bounds and if current cell is land - if i < 0 or i >= m or j < 0 or j >= n or grid[i][j] != '1': + if i < 0 or i >= m or j < 0 or j >= n or grid[i][j] != "1": return - + # Mark as visited - grid[i][j] = '0' - + grid[i][j] = "0" + # Explore all 4 directions dfs(i - 1, j) # up dfs(i + 1, j) # down dfs(i, j - 1) # left dfs(i, j + 1) # right - + # Find all islands for i in range(m): for j in range(n): - if grid[i][j] == '1': + if grid[i][j] == "1": res += 1 dfs(i, j) - - return res + return res diff --git a/solutions/201/01.py b/solutions/201/01.py index 337b389..005d31a 100644 --- a/solutions/201/01.py +++ b/solutions/201/01.py @@ -8,4 +8,3 @@ def rangeBitwiseAnd(self, left: int, right: int) -> int: shift += 1 # Shift back to get the common prefix return left << shift - diff --git a/solutions/2011/01.py b/solutions/2011/01.py index e148b8a..5744ef9 100644 --- a/solutions/2011/01.py +++ b/solutions/2011/01.py @@ -7,4 +7,3 @@ def finalValueAfterOperations(self, operations: List[str]) -> int: else: # "--X" or "X--" res -= 1 return res - diff --git a/solutions/202/01.py b/solutions/202/01.py index 9ecf52c..20732b3 100644 --- a/solutions/202/01.py +++ b/solutions/202/01.py @@ -1,12 +1,12 @@ class Solution: def isHappy(self, n: int) -> bool: seen = set() - + while n != 1: if n in seen: return False seen.add(n) - + # Calculate sum of squares of digits res = 0 while n > 0: @@ -14,6 +14,5 @@ def isHappy(self, n: int) -> bool: res += digit * digit n //= 10 n = res - - return True + return True diff --git a/solutions/2044/01.py b/solutions/2044/01.py index e96cb01..51fc889 100644 --- a/solutions/2044/01.py +++ b/solutions/2044/01.py @@ -1,24 +1,24 @@ from typing import List + class Solution: def countMaxOrSubsets(self, nums: List[int]) -> int: # Calculate maximum OR (OR of all elements) max_or = 0 for num in nums: max_or |= num - + res = 0 n = len(nums) - + # Generate all subsets using bitmask for mask in range(1, 1 << n): current_or = 0 for i in range(n): if mask & (1 << i): current_or |= nums[i] - + if current_or == max_or: res += 1 - - return res + return res diff --git a/solutions/205/01.py b/solutions/205/01.py index 1b3a0ac..3e04f8a 100644 --- a/solutions/205/01.py +++ b/solutions/205/01.py @@ -2,27 +2,27 @@ class Solution: def isIsomorphic(self, s: str, t: str) -> bool: if len(s) != len(t): return False - + # Two dictionaries to map characters from s to t and t to s s_to_t = {} t_to_s = {} - + for i in range(len(s)): char_s = s[i] char_t = t[i] - + # Check if mapping from s to t is consistent if char_s in s_to_t: if s_to_t[char_s] != char_t: return False else: s_to_t[char_s] = char_t - + # Check if mapping from t to s is consistent if char_t in t_to_s: if t_to_s[char_t] != char_s: return False else: t_to_s[char_t] = char_s - + return True diff --git a/solutions/206/01.py b/solutions/206/01.py index cec2b4c..24b58dc 100644 --- a/solutions/206/01.py +++ b/solutions/206/01.py @@ -4,11 +4,12 @@ # self.val = val # self.next = next + class Solution: def reverseList(self, head): prev = None current = head - + while current: # Store next node next_node = current.next @@ -17,5 +18,5 @@ def reverseList(self, head): # Move pointers forward prev = current current = next_node - + return prev diff --git a/solutions/207/01.py b/solutions/207/01.py index 91b175a..64ec370 100644 --- a/solutions/207/01.py +++ b/solutions/207/01.py @@ -1,31 +1,31 @@ from typing import List + class Solution: def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: # Build adjacency list graph = [[] for _ in range(numCourses)] in_degree = [0] * numCourses - + for course, prereq in prerequisites: graph[prereq].append(course) in_degree[course] += 1 - + # Find all courses with no prerequisites queue = [] for i in range(numCourses): if in_degree[i] == 0: queue.append(i) - + count = 0 while queue: course = queue.pop(0) count += 1 - + # Reduce in-degree of dependent courses for next_course in graph[course]: in_degree[next_course] -= 1 if in_degree[next_course] == 0: queue.append(next_course) - - return count == numCourses + return count == numCourses diff --git a/solutions/208/01.py b/solutions/208/01.py index fcf8a45..a6c3031 100644 --- a/solutions/208/01.py +++ b/solutions/208/01.py @@ -3,6 +3,7 @@ def __init__(self): self.children = {} self.is_end = False + class Trie: def __init__(self): self.root = TrieNode() @@ -30,4 +31,3 @@ def startsWith(self, prefix: str) -> bool: return False node = node.children[char] return True - diff --git a/solutions/209/01.py b/solutions/209/01.py index e784e24..d604bd4 100644 --- a/solutions/209/01.py +++ b/solutions/209/01.py @@ -1,18 +1,18 @@ from typing import List + class Solution: def minSubArrayLen(self, target: int, nums: List[int]) -> int: left = 0 - res = float('inf') + res = float("inf") current_sum = 0 - + for right in range(len(nums)): current_sum += nums[right] - + while current_sum >= target: res = min(res, right - left + 1) current_sum -= nums[left] left += 1 - - return res if res != float('inf') else 0 + return res if res != float("inf") else 0 diff --git a/solutions/2092/01.py b/solutions/2092/01.py index e2cb077..09a7b00 100644 --- a/solutions/2092/01.py +++ b/solutions/2092/01.py @@ -1,5 +1,7 @@ class Solution: - def findAllPeople(self, n: int, meetings: List[List[int]], firstPerson: int) -> List[int]: + def findAllPeople( + self, n: int, meetings: List[List[int]], firstPerson: int + ) -> List[int]: parent = list(range(n)) def find(x): @@ -38,4 +40,3 @@ def union(a, b): # Return all people connected to person 0 return [i for i in range(n) if find(i) == find(0)] - diff --git a/solutions/2095/01.py b/solutions/2095/01.py index b1e582b..d993551 100644 --- a/solutions/2095/01.py +++ b/solutions/2095/01.py @@ -7,16 +7,15 @@ class Solution: def deleteMiddle(self, head: Optional[ListNode]) -> Optional[ListNode]: if not head or not head.next: return None - + slow = head fast = head prev = None - + while fast and fast.next: prev = slow slow = slow.next fast = fast.next.next - + prev.next = slow.next return head - diff --git a/solutions/21/01.py b/solutions/21/01.py index 9e06251..b09d095 100644 --- a/solutions/21/01.py +++ b/solutions/21/01.py @@ -4,12 +4,13 @@ # self.val = val # self.next = next + class Solution: def mergeTwoLists(self, list1, list2): # Create a dummy node to simplify edge cases dummy = ListNode(0) current = dummy - + # Merge while both lists have nodes while list1 and list2: if list1.val <= list2.val: @@ -19,8 +20,8 @@ def mergeTwoLists(self, list1, list2): current.next = list2 list2 = list2.next current = current.next - + # Append remaining nodes current.next = list1 if list1 else list2 - + return dummy.next diff --git a/solutions/210/01.py b/solutions/210/01.py index c5b7ecc..e2471f3 100644 --- a/solutions/210/01.py +++ b/solutions/210/01.py @@ -1,31 +1,31 @@ from typing import List + class Solution: def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]: # Build adjacency list graph = [[] for _ in range(numCourses)] in_degree = [0] * numCourses - + for course, prereq in prerequisites: graph[prereq].append(course) in_degree[course] += 1 - + # Find all courses with no prerequisites queue = [] for i in range(numCourses): if in_degree[i] == 0: queue.append(i) - + res = [] while queue: course = queue.pop(0) res.append(course) - + # Reduce in-degree of dependent courses for next_course in graph[course]: in_degree[next_course] -= 1 if in_degree[next_course] == 0: queue.append(next_course) - - return res if len(res) == numCourses else [] + return res if len(res) == numCourses else [] diff --git a/solutions/211/01.py b/solutions/211/01.py index 2ce3c5d..34f1f6e 100644 --- a/solutions/211/01.py +++ b/solutions/211/01.py @@ -3,6 +3,7 @@ def __init__(self): self.children = {} self.is_end = False + class WordDictionary: def __init__(self): self.root = TrieNode() @@ -19,9 +20,9 @@ def search(self, word: str) -> bool: def dfs(node, index): if index == len(word): return node.is_end - + char = word[index] - if char == '.': + if char == ".": for child in node.children.values(): if dfs(child, index + 1): return True @@ -30,6 +31,5 @@ def dfs(node, index): if char not in node.children: return False return dfs(node.children[char], index + 1) - - return dfs(self.root, 0) + return dfs(self.root, 0) diff --git a/solutions/2110/01.py b/solutions/2110/01.py index 57f6cde..202e39f 100644 --- a/solutions/2110/01.py +++ b/solutions/2110/01.py @@ -1,22 +1,22 @@ from typing import List + class Solution: def getDescentPeriods(self, prices: List[int]) -> int: n = len(prices) res = 0 i = 0 - + while i < n: # Find the length of the current smooth descent period length = 1 while i + length < n and prices[i + length] == prices[i + length - 1] - 1: length += 1 - + # Count all subarrays within this period # For a period of length k, there are k*(k+1)//2 subarrays res += length * (length + 1) // 2 - + i += length - - return res + return res diff --git a/solutions/2119/01.py b/solutions/2119/01.py index bc85b24..d4ed89d 100644 --- a/solutions/2119/01.py +++ b/solutions/2119/01.py @@ -1,38 +1,38 @@ def minOperations(nums): """ Find the minimum number of operations to make the array continuous. - + Args: nums: List[int] - Array of integers - + Returns: int - Minimum number of operations needed """ # Handle edge case if len(nums) <= 1: return 0 - + # Sort the array to work with ordered elements nums.sort() - + # Remove duplicates to work with unique elements unique_nums = [] for i, num in enumerate(nums): - if i == 0 or num != nums[i-1]: + if i == 0 or num != nums[i - 1]: unique_nums.append(num) - + n = len(unique_nums) - min_operations = float('inf') - + min_operations = float("inf") + # Try different window sizes for i in range(n): # For each starting position, find the longest window that can be made continuous left = unique_nums[i] - + # Binary search for the rightmost element that can be part of a continuous sequence # starting from left right = left + len(nums) - 1 - + # Find how many elements in unique_nums fall within [left, right] # This gives us the size of the window that can be made continuous count = 0 @@ -41,10 +41,10 @@ def minOperations(nums): count += 1 else: break - + # Calculate operations needed # We need to change (len(nums) - count) elements operations = len(nums) - count min_operations = min(min_operations, operations) - + return min_operations diff --git a/solutions/212/01.py b/solutions/212/01.py index 7033358..c777198 100644 --- a/solutions/212/01.py +++ b/solutions/212/01.py @@ -3,8 +3,10 @@ def __init__(self): self.children = {} self.word = None + from typing import List + class Solution: def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: # Build trie @@ -16,40 +18,42 @@ def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: node.children[char] = TrieNode() node = node.children[char] node.word = word - + res = [] rows, cols = len(board), len(board[0]) - + def dfs(row, col, node): char = board[row][col] curr_node = node.children[char] - + # Check if we found a word if curr_node.word: res.append(curr_node.word) curr_node.word = None # Avoid duplicates - + # Mark as visited - board[row][col] = '#' - + board[row][col] = "#" + # Explore neighbors for dr, dc in [(0, 1), (0, -1), (1, 0), (-1, 0)]: new_row, new_col = row + dr, col + dc - if (0 <= new_row < rows and 0 <= new_col < cols and - board[new_row][new_col] in curr_node.children): + if ( + 0 <= new_row < rows + and 0 <= new_col < cols + and board[new_row][new_col] in curr_node.children + ): dfs(new_row, new_col, curr_node) - + # Restore character board[row][col] = char - + # Prune if node has no children if not curr_node.children: node.children.pop(char) - + for i in range(rows): for j in range(cols): if board[i][j] in root.children: dfs(i, j, root) - - return res + return res diff --git a/solutions/2120/01.py b/solutions/2120/01.py index 0ee4116..16544d7 100644 --- a/solutions/2120/01.py +++ b/solutions/2120/01.py @@ -2,26 +2,26 @@ class Solution: def executeInstructions(self, n: int, startPos: List[int], s: str) -> List[int]: res = [] m = len(s) - + for i in range(m): row, col = startPos[0], startPos[1] count = 0 - + for j in range(i, m): - if s[j] == 'L': + if s[j] == "L": col -= 1 - elif s[j] == 'R': + elif s[j] == "R": col += 1 - elif s[j] == 'U': + elif s[j] == "U": row -= 1 else: # 'D' row += 1 - + if row < 0 or row >= n or col < 0 or col >= n: break - + count += 1 - + res.append(count) - + return res diff --git a/solutions/2125/01.py b/solutions/2125/01.py index 710b863..109f7fd 100644 --- a/solutions/2125/01.py +++ b/solutions/2125/01.py @@ -1,19 +1,19 @@ from typing import List + class Solution: def numberOfBeams(self, bank: List[str]) -> int: # Count devices in each row device_counts = [] for row in bank: - count = row.count('1') + count = row.count("1") if count > 0: # Only include rows with devices device_counts.append(count) - + # Calculate total beams res = 0 for i in range(len(device_counts) - 1): # Beams between adjacent rows with devices res += device_counts[i] * device_counts[i + 1] - - return res + return res diff --git a/solutions/2130/01.py b/solutions/2130/01.py index 52174c0..4ff2964 100644 --- a/solutions/2130/01.py +++ b/solutions/2130/01.py @@ -9,14 +9,14 @@ def pairSum(self, head: Optional[ListNode]) -> int: while fast and fast.next: slow = slow.next fast = fast.next.next - + prev = None while slow: next_node = slow.next slow.next = prev prev = slow slow = next_node - + res = 0 first = head second = prev @@ -24,6 +24,5 @@ def pairSum(self, head: Optional[ListNode]) -> int: res = max(res, first.val + second.val) first = first.next second = second.next - - return res + return res diff --git a/solutions/2147/01.py b/solutions/2147/01.py index f420d80..123f715 100644 --- a/solutions/2147/01.py +++ b/solutions/2147/01.py @@ -1,35 +1,35 @@ class Solution: def numberOfWays(self, corridor: str) -> int: MOD = 10**9 + 7 - + # Count total seats - seat_count = corridor.count('S') - + seat_count = corridor.count("S") + # If total seats is odd or zero, no valid division if seat_count == 0 or seat_count % 2 != 0: return 0 - + res = 1 seats_seen = 0 i = 0 - + # Process the corridor while i < len(corridor): - if corridor[i] == 'S': + if corridor[i] == "S": seats_seen += 1 - + # When we've seen 2 seats, we've completed a segment if seats_seen == 2: # Look ahead to find the next segment (next 2 seats) # Count plants between current segment and next segment plants_between = 0 j = i + 1 - + # Skip plants until we find the next seat - while j < len(corridor) and corridor[j] == 'P': + while j < len(corridor) and corridor[j] == "P": plants_between += 1 j += 1 - + # If we found another seat (meaning there's a next segment) if j < len(corridor): # We can place divider in (plants_between + 1) positions @@ -38,5 +38,5 @@ def numberOfWays(self, corridor: str) -> int: seats_seen = 0 # Reset for next segment i = j - 1 # Will be incremented by loop i += 1 - + return res diff --git a/solutions/215/01.py b/solutions/215/01.py index e49a051..3ddb5cb 100644 --- a/solutions/215/01.py +++ b/solutions/215/01.py @@ -1,17 +1,17 @@ from typing import List import heapq + class Solution: def findKthLargest(self, nums: List[int], k: int) -> int: # Use a min heap of size k heap = [] - + for num in nums: if len(heap) < k: heapq.heappush(heap, num) elif num > heap[0]: heapq.heapreplace(heap, num) - + # The kth largest is at the top of the min heap return heap[0] - diff --git a/solutions/216/01.py b/solutions/216/01.py index 10a8a46..a3feb44 100644 --- a/solutions/216/01.py +++ b/solutions/216/01.py @@ -1,20 +1,19 @@ class Solution: def combinationSum3(self, k: int, n: int) -> List[List[int]]: res = [] - + def backtrack(start, path, remaining): if len(path) == k and remaining == 0: res.append(path[:]) return - + if len(path) >= k or remaining < 0: return - + for i in range(start, 10): path.append(i) backtrack(i + 1, path, remaining - i) path.pop() - + backtrack(1, [], n) return res - diff --git a/solutions/2161/01.py b/solutions/2161/01.py index ecb244f..48a0468 100644 --- a/solutions/2161/01.py +++ b/solutions/2161/01.py @@ -1,11 +1,12 @@ from typing import List + class Solution: def pivotArray(self, nums: List[int], pivot: int) -> List[int]: less = [] equal = [] greater = [] - + # Partition elements into three groups for num in nums: if num < pivot: @@ -14,8 +15,7 @@ def pivotArray(self, nums: List[int], pivot: int) -> List[int]: equal.append(num) else: greater.append(num) - + # Combine in order: less, equal, greater res = less + equal + greater return res - diff --git a/solutions/2181/01.py b/solutions/2181/01.py index 715e4f7..35ae073 100644 --- a/solutions/2181/01.py +++ b/solutions/2181/01.py @@ -5,28 +5,28 @@ # self.next = next from typing import Optional + class Solution: def mergeNodes(self, head: Optional[ListNode]) -> Optional[ListNode]: # Skip the first zero current = head.next dummy = ListNode(0) tail = dummy - + while current: # Sum values until we hit the next zero total = 0 while current and current.val != 0: total += current.val current = current.next - + # Create new node with the sum if total > 0: tail.next = ListNode(total) tail = tail.next - + # Move past the zero if current: current = current.next - - return dummy.next + return dummy.next diff --git a/solutions/219/01.py b/solutions/219/01.py index 1b72501..3a4900c 100644 --- a/solutions/219/01.py +++ b/solutions/219/01.py @@ -1,6 +1,6 @@ def containsNearbyDuplicate(nums: list[int], k: int) -> bool: window_set = set() - + for i, num in enumerate(nums): if i > k: window_set.remove(nums[i - k - 1]) @@ -8,8 +8,8 @@ def containsNearbyDuplicate(nums: list[int], k: int) -> bool: if num in window_set: res = True return res - + window_set.add(num) - + res = False - return res \ No newline at end of file + return res diff --git a/solutions/22/01.py b/solutions/22/01.py index 4fe3d6d..030644f 100644 --- a/solutions/22/01.py +++ b/solutions/22/01.py @@ -1,23 +1,23 @@ from typing import List + class Solution: def generateParenthesis(self, n: int) -> List[str]: res = [] - + def backtrack(current, open_count, close_count): # Base case: valid combination found if len(current) == 2 * n: res.append(current) return - + # Add opening parenthesis if we haven't used all if open_count < n: backtrack(current + "(", open_count + 1, close_count) - + # Add closing parenthesis if valid (more opens than closes) if close_count < open_count: backtrack(current + ")", open_count, close_count + 1) - + backtrack("", 0, 0) return res - diff --git a/solutions/221/01.py b/solutions/221/01.py index b5f3b59..94e4ff9 100644 --- a/solutions/221/01.py +++ b/solutions/221/01.py @@ -1,22 +1,22 @@ from typing import List + class Solution: def maximalSquare(self, matrix: List[List[str]]) -> int: if not matrix: return 0 - + rows, cols = len(matrix), len(matrix[0]) dp = [[0] * cols for _ in range(rows)] res = 0 - + for i in range(rows): for j in range(cols): - if matrix[i][j] == '1': + if matrix[i][j] == "1": if i == 0 or j == 0: dp[i][j] = 1 else: - dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1 + dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1 res = max(res, dp[i][j]) - - return res * res + return res * res diff --git a/solutions/2211/01.py b/solutions/2211/01.py index ac7a466..0d286a5 100644 --- a/solutions/2211/01.py +++ b/solutions/2211/01.py @@ -3,17 +3,16 @@ def countCollisions(self, directions: str) -> int: # Remove leading L's (moving left, will never collide) # Remove trailing R's (moving right, will never collide) # Only cars in the middle section will collide - directions = directions.lstrip('L').rstrip('R') - + directions = directions.lstrip("L").rstrip("R") + if not directions: return 0 - + res = 0 # Count all non-stationary cars in the middle section # Each R or L in the middle will eventually collide for char in directions: - if char != 'S': + if char != "S": res += 1 - - return res + return res diff --git a/solutions/2215/01.py b/solutions/2215/01.py index f63c3cd..96fffa0 100644 --- a/solutions/2215/01.py +++ b/solutions/2215/01.py @@ -1,3 +1,3 @@ def findDifference(nums1, nums2): set1, set2 = set(nums1), set(nums2) - return [list(set1 - set2), list(set2 - set1)] \ No newline at end of file + return [list(set1 - set2), list(set2 - set1)] diff --git a/solutions/222/01.py b/solutions/222/01.py index 3dd9005..a5c9404 100644 --- a/solutions/222/01.py +++ b/solutions/222/01.py @@ -7,26 +7,26 @@ # self.left = left # self.right = right + class Solution: def countNodes(self, root: Optional[TreeNode]) -> int: if not root: return 0 - + # Get left and right heights left_height = self.get_height(root.left) right_height = self.get_height(root.right) - + if left_height == right_height: # Left subtree is full, right subtree may not be return (1 << left_height) + self.countNodes(root.right) else: # Right subtree is full, left subtree may not be return (1 << right_height) + self.countNodes(root.left) - + def get_height(self, node): height = 0 while node: height += 1 node = node.left return height - diff --git a/solutions/224/01.py b/solutions/224/01.py index f799d52..26aa591 100644 --- a/solutions/224/01.py +++ b/solutions/224/01.py @@ -4,28 +4,27 @@ def calculate(self, s: str) -> int: res = 0 num = 0 sign = 1 - + for char in s: if char.isdigit(): num = num * 10 + int(char) - elif char == '+': + elif char == "+": res += sign * num num = 0 sign = 1 - elif char == '-': + elif char == "-": res += sign * num num = 0 sign = -1 - elif char == '(': + elif char == "(": stack.append(res) stack.append(sign) res = 0 sign = 1 - elif char == ')': + elif char == ")": res += sign * num num = 0 res *= stack.pop() # pop sign res += stack.pop() # pop previous result - - return res + sign * num + return res + sign * num diff --git a/solutions/226/01.py b/solutions/226/01.py index 75bc73b..ddb4235 100644 --- a/solutions/226/01.py +++ b/solutions/226/01.py @@ -7,16 +7,17 @@ # self.left = left # self.right = right + class Solution: def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]: if not root: return None - + # Swap left and right children root.left, root.right = root.right, root.left - + # Recursively invert subtrees self.invertTree(root.left) self.invertTree(root.right) - + return root diff --git a/solutions/2265/01.py b/solutions/2265/01.py index c6aac00..9a6d3b5 100644 --- a/solutions/2265/01.py +++ b/solutions/2265/01.py @@ -7,29 +7,28 @@ class Solution: def averageOfSubtree(self, root: TreeNode) -> int: res = 0 - + def dfs(node): nonlocal res if not node: return 0, 0 # sum, count - + # Get subtree info from children left_sum, left_count = dfs(node.left) right_sum, right_count = dfs(node.right) - + # Calculate current subtree sum and count subtree_sum = node.val + left_sum + right_sum subtree_count = 1 + left_count + right_count - + # Calculate average (integer division) avg = subtree_sum // subtree_count - + # Check if node value equals average if node.val == avg: res += 1 - + return subtree_sum, subtree_count - + dfs(root) return res - diff --git a/solutions/228/01.py b/solutions/228/01.py index 2c1c31d..aec12e7 100644 --- a/solutions/228/01.py +++ b/solutions/228/01.py @@ -1,24 +1,24 @@ def summaryRanges(nums): """ Create a summary of ranges from a sorted array of unique integers. - + Args: nums: List[int] - Sorted array of unique integers - + Returns: List[str] - List of range strings """ # Handle edge case if not nums: return [] - + result = [] start = 0 - + # Traverse array looking for consecutive sequences for i in range(1, len(nums)): # Check if current number is consecutive to previous - if nums[i] != nums[i-1] + 1: + if nums[i] != nums[i - 1] + 1: # Break in sequence, format the range if start == i - 1: # Single number @@ -26,10 +26,10 @@ def summaryRanges(nums): else: # Range of numbers result.append(f"{nums[start]}->{nums[i-1]}") - + # Start new range start = i - + # Handle the final range if start == len(nums) - 1: # Single number @@ -37,5 +37,5 @@ def summaryRanges(nums): else: # Range of numbers result.append(f"{nums[start]}->{nums[-1]}") - + return result diff --git a/solutions/23/01.py b/solutions/23/01.py index 727ed96..98fbf8f 100644 --- a/solutions/23/01.py +++ b/solutions/23/01.py @@ -7,29 +7,29 @@ from typing import List import heapq + class Solution: def mergeKLists(self, lists: List[ListNode]) -> ListNode: # Create a min heap heap = [] - + # Add first node from each list to heap for i, node in enumerate(lists): if node: heapq.heappush(heap, (node.val, i, node)) - + # Create dummy node dummy = ListNode(0) current = dummy - + # Merge lists while heap: val, idx, node = heapq.heappop(heap) current.next = node current = current.next - + # Add next node from the same list if it exists if node.next: heapq.heappush(heap, (node.next.val, idx, node.next)) - - return dummy.next + return dummy.next diff --git a/solutions/230/01.py b/solutions/230/01.py index bd1e730..3ba41d4 100644 --- a/solutions/230/01.py +++ b/solutions/230/01.py @@ -5,21 +5,20 @@ # self.left = left # self.right = right + class Solution: def kthSmallest(self, root, k: int) -> int: # In-order traversal to get elements in sorted order res = [] - + def inorder(node): if not node: return inorder(node.left) res.append(node.val) inorder(node.right) - + inorder(root) - + # Return the k-th smallest element (1-indexed) return res[k - 1] - - diff --git a/solutions/2300/01.py b/solutions/2300/01.py index 210af16..0a73249 100644 --- a/solutions/2300/01.py +++ b/solutions/2300/01.py @@ -1,9 +1,11 @@ class Solution: - def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]: + def successfulPairs( + self, spells: List[int], potions: List[int], success: int + ) -> List[int]: potions.sort() res = [] n = len(potions) - + for spell in spells: target = (success + spell - 1) // spell left, right = 0, n @@ -14,6 +16,5 @@ def successfulPairs(self, spells: List[int], potions: List[int], success: int) - else: right = mid res.append(n - left) - - return res + return res diff --git a/solutions/2326/01.py b/solutions/2326/01.py index 04e1bcc..eb741c8 100644 --- a/solutions/2326/01.py +++ b/solutions/2326/01.py @@ -6,29 +6,33 @@ class Solution: def spiralMatrix(self, m: int, n: int, head: Optional[ListNode]) -> List[List[int]]: res = [[-1] * n for _ in range(m)] - + directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] dir_idx = 0 row, col = 0, 0 - + while head: res[row][col] = head.val head = head.next - + if not head: break - + # Try to move in current direction next_row = row + directions[dir_idx][0] next_col = col + directions[dir_idx][1] - + # Check if we need to change direction - if (next_row < 0 or next_row >= m or - next_col < 0 or next_col >= n or - res[next_row][next_col] != -1): + if ( + next_row < 0 + or next_row >= m + or next_col < 0 + or next_col >= n + or res[next_row][next_col] != -1 + ): dir_idx = (dir_idx + 1) % 4 - + row += directions[dir_idx][0] col += directions[dir_idx][1] - + return res diff --git a/solutions/2336/01.py b/solutions/2336/01.py index 0f25d2a..8c9529b 100644 --- a/solutions/2336/01.py +++ b/solutions/2336/01.py @@ -1,5 +1,6 @@ import heapq + class SmallestInfiniteSet: def __init__(self): @@ -22,4 +23,3 @@ def addBack(self, num: int) -> None: if num in self.removed: self.removed.remove(num) heapq.heappush(self.added_back, num) - diff --git a/solutions/234/01.py b/solutions/234/01.py index 55baf3a..1bd46be 100644 --- a/solutions/234/01.py +++ b/solutions/234/01.py @@ -11,7 +11,7 @@ def isPalindrome(self, head: Optional[ListNode]) -> bool: while current: values.append(current.val) current = current.next - + # Check if array is palindrome left, right = 0, len(values) - 1 while left < right: @@ -19,6 +19,5 @@ def isPalindrome(self, head: Optional[ListNode]) -> bool: return False left += 1 right -= 1 - - return True + return True diff --git a/solutions/235/01.py b/solutions/235/01.py index b4e57c6..1615dc0 100644 --- a/solutions/235/01.py +++ b/solutions/235/01.py @@ -5,16 +5,16 @@ # self.left = left # self.right = right + class Solution: def lowestCommonAncestor(self, root, p, q): # If both p and q are less than root, LCA is in left subtree if p.val < root.val and q.val < root.val: return self.lowestCommonAncestor(root.left, p, q) - + # If both p and q are greater than root, LCA is in right subtree if p.val > root.val and q.val > root.val: return self.lowestCommonAncestor(root.right, p, q) - + # Otherwise, root is the LCA return root - diff --git a/solutions/236/01.py b/solutions/236/01.py index 0bf91b0..e3eab01 100644 --- a/solutions/236/01.py +++ b/solutions/236/01.py @@ -5,20 +5,22 @@ # self.left = None # self.right = None + class Solution: - def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + def lowestCommonAncestor( + self, root: "TreeNode", p: "TreeNode", q: "TreeNode" + ) -> "TreeNode": # Base case: if root is None or root is p or q, return root if not root or root == p or root == q: return root - + # Recursively search in left and right subtrees left = self.lowestCommonAncestor(root.left, p, q) right = self.lowestCommonAncestor(root.right, p, q) - + # If both left and right return non-None, root is the LCA if left and right: return root - + # Otherwise, return whichever side found p or q return left if left else right - diff --git a/solutions/237/01.py b/solutions/237/01.py index f9bbb08..71ad7c7 100644 --- a/solutions/237/01.py +++ b/solutions/237/01.py @@ -4,6 +4,7 @@ # self.val = x # self.next = None + class Solution: def deleteNode(self, node): """ diff --git a/solutions/238/01.py b/solutions/238/01.py index 54587bf..1524d0a 100644 --- a/solutions/238/01.py +++ b/solutions/238/01.py @@ -1,18 +1,19 @@ from typing import List + class Solution: def productExceptSelf(self, nums: List[int]) -> List[int]: n = len(nums) res = [1] * n - + # First pass: calculate left products for i in range(1, n): res[i] = res[i - 1] * nums[i - 1] - + # Second pass: calculate right products and multiply right_product = 1 for i in range(n - 1, -1, -1): res[i] *= right_product right_product *= nums[i] - + return res diff --git a/solutions/239/01.py b/solutions/239/01.py index edc9dce..fe71fb6 100644 --- a/solutions/239/01.py +++ b/solutions/239/01.py @@ -1,27 +1,27 @@ from collections import deque from typing import List + class Solution: def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]: # Use deque to maintain indices of elements in decreasing order dq = deque() res = [] - + for i in range(len(nums)): # Remove indices outside the current window while dq and dq[0] <= i - k: dq.popleft() - + # Remove indices whose corresponding values are smaller than current while dq and nums[dq[-1]] < nums[i]: dq.pop() - + # Add current index dq.append(i) - + # If we've processed at least k elements, add max to result if i >= k - 1: res.append(nums[dq[0]]) - - return res + return res diff --git a/solutions/2390/01.py b/solutions/2390/01.py index ab09375..14d252f 100644 --- a/solutions/2390/01.py +++ b/solutions/2390/01.py @@ -1,16 +1,16 @@ class Solution: def removeStars(self, s: str) -> str: stack = [] - + for char in s: - if char == '*': + if char == "*": # Remove the closest non-star character to the left if stack: stack.pop() else: # Push non-star characters onto the stack stack.append(char) - + # Convert stack to string - res = ''.join(stack) + res = "".join(stack) return res diff --git a/solutions/240/01.py b/solutions/240/01.py index da820d3..99d98bc 100644 --- a/solutions/240/01.py +++ b/solutions/240/01.py @@ -2,11 +2,11 @@ class Solution: def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: if not matrix or not matrix[0]: return False - + m, n = len(matrix), len(matrix[0]) # Start from top-right corner row, col = 0, n - 1 - + while row < m and col >= 0: if matrix[row][col] == target: return True @@ -16,6 +16,5 @@ def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: else: # Current element is too small, move down row += 1 - - return False + return False diff --git a/solutions/2419/01.py b/solutions/2419/01.py index 72ce140..3b5e1c1 100644 --- a/solutions/2419/01.py +++ b/solutions/2419/01.py @@ -8,4 +8,4 @@ def longestSubarray(nums: List[int]) -> int: res = max(res, size) else: size = 0 - return res \ No newline at end of file + return res diff --git a/solutions/242/01.py b/solutions/242/01.py index 2e3e4ee..fb5ec0f 100644 --- a/solutions/242/01.py +++ b/solutions/242/01.py @@ -1,25 +1,25 @@ def isAnagram(s, t): if len(s) != len(t): return False - + char_count = {} - + for char in s: char_count[char] = char_count.get(char, 0) + 1 - + for char in t: if char not in char_count: return False - + char_count[char] -= 1 - + # If count becomes negative, strings are not anagrams if char_count[char] < 0: return False - + # Check if all counts are zero for count in char_count.values(): if count != 0: return False - + return True diff --git a/solutions/2433/01.py b/solutions/2433/01.py index fee5419..b13418f 100644 --- a/solutions/2433/01.py +++ b/solutions/2433/01.py @@ -1,17 +1,17 @@ from typing import List + class Solution: def findArray(self, pref: List[int]) -> List[int]: n = len(pref) res = [0] * n res[0] = pref[0] - + # For each position i, we have: pref[i] = res[0] ^ res[1] ^ ... ^ res[i] # We know: pref[i-1] = res[0] ^ res[1] ^ ... ^ res[i-1] # Therefore: pref[i] = pref[i-1] ^ res[i] # So: res[i] = pref[i] ^ pref[i-1] for i in range(1, n): - res[i] = pref[i] ^ pref[i-1] - - return res + res[i] = pref[i] ^ pref[i - 1] + return res diff --git a/solutions/2462/01.py b/solutions/2462/01.py index 79106b1..9876590 100644 --- a/solutions/2462/01.py +++ b/solutions/2462/01.py @@ -1,18 +1,19 @@ from typing import List import heapq + class Solution: def totalCost(self, costs: List[int], k: int, candidates: int) -> int: n = len(costs) res = 0 - + # Use two heaps for left and right candidates left_heap = [] right_heap = [] - + left_idx = 0 right_idx = n - 1 - + # Initialize heaps with first and last candidates for _ in range(candidates): if left_idx <= right_idx: @@ -21,7 +22,7 @@ def totalCost(self, costs: List[int], k: int, candidates: int) -> int: if left_idx <= right_idx: heapq.heappush(right_heap, costs[right_idx]) right_idx -= 1 - + # Hire k workers for _ in range(k): # Choose the minimum from left or right heap @@ -37,6 +38,5 @@ def totalCost(self, costs: List[int], k: int, candidates: int) -> int: if left_idx <= right_idx: heapq.heappush(right_heap, costs[right_idx]) right_idx -= 1 - - return res + return res diff --git a/solutions/2482/01.py b/solutions/2482/01.py index 451639a..c2f3230 100644 --- a/solutions/2482/01.py +++ b/solutions/2482/01.py @@ -1,17 +1,17 @@ class Solution: def onesMinusZeros(self, grid: List[List[int]]) -> List[List[int]]: m, n = len(grid), len(grid[0]) - + # Count ones in each row and column onesRow = [0] * m onesCol = [0] * n - + for i in range(m): for j in range(n): if grid[i][j] == 1: onesRow[i] += 1 onesCol[j] += 1 - + # Build result matrix res = [[0] * n for _ in range(m)] for i in range(m): @@ -19,5 +19,5 @@ def onesMinusZeros(self, grid: List[List[int]]) -> List[List[int]]: for j in range(n): zerosCol = m - onesCol[j] res[i][j] = onesRow[i] + onesCol[j] - zerosRow - zerosCol - + return res diff --git a/solutions/25/01.py b/solutions/25/01.py index c9665c1..52afd37 100644 --- a/solutions/25/01.py +++ b/solutions/25/01.py @@ -5,6 +5,7 @@ # self.next = next from typing import Optional + class Solution: def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: # Helper function to reverse a linked list segment @@ -17,14 +18,14 @@ def reverse_segment(start, end): prev = curr curr = next_node return prev - + # Count nodes to check if we have enough for a group count = 0 curr = head while curr and count < k: curr = curr.next count += 1 - + # If we have k nodes, reverse them if count == k: # Reverse the first k nodes @@ -32,7 +33,6 @@ def reverse_segment(start, end): # Recursively reverse the rest head.next = self.reverseKGroup(curr, k) return reversed_head - + # Not enough nodes, return as is return head - diff --git a/solutions/2542/01.py b/solutions/2542/01.py index 016e3a0..6aa15a6 100644 --- a/solutions/2542/01.py +++ b/solutions/2542/01.py @@ -2,26 +2,27 @@ class Solution: def maxScore(self, nums1: List[int], nums2: List[int], k: int) -> int: # Sort pairs by nums2 in descending order pairs = sorted(zip(nums1, nums2), key=lambda x: x[1], reverse=True) - + import heapq + # Use min heap to maintain k largest nums1 values heap = [] res = 0 current_sum = 0 - + for num1, num2 in pairs: # Add current num1 to heap and sum heapq.heappush(heap, num1) current_sum += num1 - + # If we have more than k elements, remove the smallest if len(heap) > k: current_sum -= heapq.heappop(heap) - + # If we have exactly k elements, calculate score if len(heap) == k: # num2 is the minimum in current selection (since we sorted descending) score = current_sum * num2 res = max(res, score) - + return res diff --git a/solutions/2627/01.py b/solutions/2627/01.py index 5214891..428e424 100644 --- a/solutions/2627/01.py +++ b/solutions/2627/01.py @@ -9,13 +9,13 @@ */ var debounce = function(fn, t) { let timeoutId = null; - + return function(...args) { // Clear any existing timeout if (timeoutId !== null) { clearTimeout(timeoutId); } - + // Set new timeout timeoutId = setTimeout(() => { fn(...args); diff --git a/solutions/2637/01.py b/solutions/2637/01.py index 6527b7f..3d2d869 100644 --- a/solutions/2637/01.py +++ b/solutions/2637/01.py @@ -1,14 +1,15 @@ from typing import List + class Solution: def rowAndMaximumOnes(self, mat: List[List[int]]) -> List[int]: max_ones = -1 max_row = -1 - + for i, row in enumerate(mat): ones = sum(row) if ones > max_ones: max_ones = ones max_row = i - + return [max_row, max_ones] diff --git a/solutions/2657/01.py b/solutions/2657/01.py index 47c2cec..1688cc8 100644 --- a/solutions/2657/01.py +++ b/solutions/2657/01.py @@ -1,20 +1,20 @@ from typing import List + class Solution: def findThePrefixCommonArray(self, A: List[int], B: List[int]) -> List[int]: n = len(A) res = [] seen_a = set() seen_b = set() - + for i in range(n): # Add current elements to sets seen_a.add(A[i]) seen_b.add(B[i]) - + # Count common elements common = len(seen_a & seen_b) res.append(common) - - return res + return res diff --git a/solutions/2723/01.py b/solutions/2723/01.py index fa98f4a..4c3d970 100644 --- a/solutions/2723/01.py +++ b/solutions/2723/01.py @@ -11,10 +11,10 @@ # For Python, we can simulate this with asyncio import asyncio + class Solution: async def addTwoPromises(self, promise1, promise2): val1 = await promise1 val2 = await promise2 res = val1 + val2 return res - diff --git a/solutions/274/01.py b/solutions/274/01.py index 26181a6..72b45a2 100644 --- a/solutions/274/01.py +++ b/solutions/274/01.py @@ -1,33 +1,33 @@ def hIndex(citations): """ Calculate the h-index for a researcher based on their paper citations. - + Args: citations: List[int] - Array of citation counts for each paper - + Returns: int - The researcher's h-index """ # Handle edge cases if not citations: return 0 - + # Sort citations in descending order citations.sort(reverse=True) - + # Check each position as a potential h-index for i in range(len(citations)): # h-index is i + 1 (1-indexed) h = i + 1 - + # Check if citations[i] >= h # If not, we've found our answer if citations[i] < h: return i - + # If we reach the end, the h-index is the length of the array if i == len(citations) - 1: return h - + # This line should never be reached return 0 diff --git a/solutions/2769/01.py b/solutions/2769/01.py index ec5aea5..e4344bc 100644 --- a/solutions/2769/01.py +++ b/solutions/2769/01.py @@ -6,4 +6,3 @@ def theMaximumAchievableX(self, num: int, t: int) -> int: # Therefore: x = num + 2 * t res = num + 2 * t return res - diff --git a/solutions/278/01.py b/solutions/278/01.py index 2679fd9..5cc8f4f 100644 --- a/solutions/278/01.py +++ b/solutions/278/01.py @@ -1,20 +1,20 @@ # The isBadVersion API is already defined for you. # def isBadVersion(version: int) -> bool: + class Solution: def firstBadVersion(self, n: int) -> int: left = 1 right = n - + while left < right: mid = (left + right) // 2 - + if isBadVersion(mid): # Mid is bad, so first bad is at mid or before right = mid else: # Mid is good, so first bad is after mid left = mid + 1 - - return left + return left diff --git a/solutions/2785/01.py b/solutions/2785/01.py index 3e7bd60..13c28d5 100644 --- a/solutions/2785/01.py +++ b/solutions/2785/01.py @@ -1,11 +1,11 @@ class Solution: def sortVowels(self, s: str) -> str: - vowels = {'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'} - + vowels = {"a", "e", "i", "o", "u", "A", "E", "I", "O", "U"} + # Extract and sort vowels vowel_list = [c for c in s if c in vowels] vowel_list.sort() - + # Build result res = [] vowel_idx = 0 @@ -15,5 +15,5 @@ def sortVowels(self, s: str) -> str: vowel_idx += 1 else: res.append(c) - - return ''.join(res) + + return "".join(res) diff --git a/solutions/28/01.py b/solutions/28/01.py index 7ef5557..203be49 100644 --- a/solutions/28/01.py +++ b/solutions/28/01.py @@ -3,12 +3,11 @@ def strStr(self, haystack: str, needle: str) -> int: # Simple string matching n = len(haystack) m = len(needle) - + # Check each possible starting position for i in range(n - m + 1): - if haystack[i:i + m] == needle: + if haystack[i : i + m] == needle: return i - + # Not found return -1 - diff --git a/solutions/2807/01.py b/solutions/2807/01.py index 0a15230..adaa57c 100644 --- a/solutions/2807/01.py +++ b/solutions/2807/01.py @@ -5,27 +5,30 @@ # self.next = next from typing import Optional + class Solution: - def insertGreatestCommonDivisors(self, head: Optional[ListNode]) -> Optional[ListNode]: + def insertGreatestCommonDivisors( + self, head: Optional[ListNode] + ) -> Optional[ListNode]: def gcd(a, b): while b: a, b = b, a % b return a - + current = head - + while current and current.next: # Calculate GCD of current and next node values gcd_value = gcd(current.val, current.next.val) - + # Create new node with GCD value new_node = ListNode(gcd_value) - + # Insert new node between current and current.next new_node.next = current.next current.next = new_node - + # Move to the node after the inserted one current = new_node.next - + return head diff --git a/solutions/283/01.py b/solutions/283/01.py index bc59e94..c496bc8 100644 --- a/solutions/283/01.py +++ b/solutions/283/01.py @@ -1,10 +1,11 @@ from typing import List + class Solution: def moveZeroes(self, nums: List[int]) -> None: # Two pointers: one for current position, one for next non-zero position next_non_zero = 0 - + # Move all non-zero elements to the front for i in range(len(nums)): if nums[i] != 0: diff --git a/solutions/287/01.py b/solutions/287/01.py index 4e2478e..d1cde36 100644 --- a/solutions/287/01.py +++ b/solutions/287/01.py @@ -2,19 +2,18 @@ class Solution: def findDuplicate(self, nums: List[int]) -> int: # Floyd's cycle detection (tortoise and hare) slow = fast = nums[0] - + # Find the intersection point in the cycle while True: slow = nums[slow] fast = nums[nums[fast]] if slow == fast: break - + # Find the entrance to the cycle slow = nums[0] while slow != fast: slow = nums[slow] fast = nums[fast] - - return slow + return slow diff --git a/solutions/2879/01.py b/solutions/2879/01.py index 894481a..0cb1446 100644 --- a/solutions/2879/01.py +++ b/solutions/2879/01.py @@ -1,6 +1,6 @@ import pandas as pd + def selectFirstRows(employees: pd.DataFrame) -> pd.DataFrame: res = employees.head(3) return res - diff --git a/solutions/2884/01.py b/solutions/2884/01.py index ebd1bd0..c2babbc 100644 --- a/solutions/2884/01.py +++ b/solutions/2884/01.py @@ -1,7 +1,7 @@ import pandas as pd + def modifySalaryColumn(employees: pd.DataFrame) -> pd.DataFrame: - employees['salary'] = employees['salary'] * 2 + employees["salary"] = employees["salary"] * 2 res = employees return res - diff --git a/solutions/2888/01.py b/solutions/2888/01.py index 053fa06..2a5904e 100644 --- a/solutions/2888/01.py +++ b/solutions/2888/01.py @@ -1,26 +1,25 @@ class Solution: def minimumIndex(self, nums: List[int]) -> int: from collections import Counter - + # Find the dominant element count = Counter(nums) dominant = max(count, key=count.get) total_freq = count[dominant] - + # Track frequency in left subarray left_freq = 0 - + for i in range(len(nums) - 1): if nums[i] == dominant: left_freq += 1 - + right_freq = total_freq - left_freq left_len = i + 1 right_len = len(nums) - left_len - + # Check if dominant in both subarrays if left_freq * 2 > left_len and right_freq * 2 > right_len: return i - - return -1 + return -1 diff --git a/solutions/289/01.py b/solutions/289/01.py index efcbb22..f510332 100644 --- a/solutions/289/01.py +++ b/solutions/289/01.py @@ -2,32 +2,32 @@ def gameOfLife(board): """ Update the board to the next generation of Conway's Game of Life. This is done in-place using O(1) space. - + Args: board: List[List[int]] - The board to update in-place - + Returns: None - Modifies the board in-place """ if not board or not board[0]: return - + m, n = len(board), len(board[0]) - + # First pass: mark cells with their next state using special values # 2 = currently live, will die (live→dead) # 3 = currently dead, will live (dead→live) for i in range(m): for j in range(n): live_neighbors = countLiveNeighbors(board, i, j, m, n) - + if board[i][j] == 1: # Currently live if live_neighbors < 2 or live_neighbors > 3: board[i][j] = 2 # Mark as live→dead else: # Currently dead if live_neighbors == 3: board[i][j] = 3 # Mark as dead→live - + # Second pass: convert special values to final states for i in range(m): for j in range(n): @@ -40,27 +40,31 @@ def gameOfLife(board): def countLiveNeighbors(board, i, j, m, n): """ Count the number of live neighbors for a given cell. - + Args: board: List[List[int]] - The game board i, j: int - Row and column indices of the cell m, n: int - Dimensions of the board - + Returns: int - Number of live neighbors """ count = 0 - + # Check all 8 neighbors for di in [-1, 0, 1]: for dj in [-1, 0, 1]: if di == 0 and dj == 0: # Skip the cell itself continue - + ni, nj = i + di, j + dj - + # Check bounds - if 0 <= ni < m and 0 <= nj < n and (board[ni][nj] == 1 or board[ni][nj] == 2): + if ( + 0 <= ni < m + and 0 <= nj < n + and (board[ni][nj] == 1 or board[ni][nj] == 2) + ): count += 1 - + return count diff --git a/solutions/2894/01.py b/solutions/2894/01.py index 39667a7..c20e1c4 100644 --- a/solutions/2894/01.py +++ b/solutions/2894/01.py @@ -2,13 +2,12 @@ class Solution: def differenceOfSums(self, n: int, m: int) -> int: num1 = 0 # Sum of numbers not divisible by m num2 = 0 # Sum of numbers divisible by m - + for i in range(1, n + 1): if i % m == 0: num2 += i else: num1 += i - + res = num1 - num2 return res - diff --git a/solutions/290/01.py b/solutions/290/01.py index 48897be..ed2995d 100644 --- a/solutions/290/01.py +++ b/solutions/290/01.py @@ -1,30 +1,30 @@ def wordPattern(pattern, s): """ Determine if the string s follows the given pattern. - + Args: pattern: str - The pattern string to match against s: str - The string of space-separated words - + Returns: bool - True if s follows the pattern, False otherwise """ # Split the string into words words = s.split() - + # Check if pattern length matches word count if len(pattern) != len(words): return False - + # Create mapping dictionaries for both directions char_to_word = {} # maps pattern characters to words word_to_char = {} # maps words to pattern characters - + # Check each character-word pair for i in range(len(pattern)): char = pattern[i] word = words[i] - + # Check if char is already mapped if char in char_to_word: # Verify the mapping is consistent @@ -34,9 +34,9 @@ def wordPattern(pattern, s): # Check if word is already mapped to by another character if word in word_to_char: return False - + # Add new mapping char_to_word[char] = word word_to_char[word] = char - + return True diff --git a/solutions/2942/01.py b/solutions/2942/01.py index af3cc18..544983e 100644 --- a/solutions/2942/01.py +++ b/solutions/2942/01.py @@ -5,4 +5,3 @@ def findWordsContaining(self, words: List[str], x: str) -> List[int]: if x in word: res.append(i) return res - diff --git a/solutions/295/01.py b/solutions/295/01.py index e179fb1..477acac 100644 --- a/solutions/295/01.py +++ b/solutions/295/01.py @@ -1,5 +1,6 @@ import heapq + class MedianFinder: def __init__(self): # max_heap for smaller half, min_heap for larger half @@ -11,7 +12,7 @@ def addNum(self, num: int) -> None: heapq.heappush(self.max_heap, -num) else: heapq.heappush(self.min_heap, num) - + # Balance heaps if len(self.max_heap) > len(self.min_heap) + 1: heapq.heappush(self.min_heap, -heapq.heappop(self.max_heap)) @@ -25,4 +26,3 @@ def findMedian(self) -> float: return float(-self.max_heap[0]) else: return float(self.min_heap[0]) - diff --git a/solutions/297/01.py b/solutions/297/01.py index 0be7a80..ae03cbb 100644 --- a/solutions/297/01.py +++ b/solutions/297/01.py @@ -5,20 +5,21 @@ # self.left = None # self.right = None + class Codec: def serialize(self, root): """Encodes a tree to a single string. - + :type root: TreeNode :rtype: str """ if not root: return "" - + res = [] queue = [root] - + while queue: node = queue.pop(0) if node: @@ -27,35 +28,34 @@ def serialize(self, root): queue.append(node.right) else: res.append("null") - + return ",".join(res) def deserialize(self, data): """Decodes your encoded data to tree. - + :type data: str :rtype: TreeNode """ if not data: return None - + values = data.split(",") root = TreeNode(int(values[0])) queue = [root] i = 1 - + while queue and i < len(values): node = queue.pop(0) - + if values[i] != "null": node.left = TreeNode(int(values[i])) queue.append(node.left) i += 1 - + if i < len(values) and values[i] != "null": node.right = TreeNode(int(values[i])) queue.append(node.right) i += 1 - - return root + return root diff --git a/solutions/3/01.py b/solutions/3/01.py index 2b6ff31..aa9966c 100644 --- a/solutions/3/01.py +++ b/solutions/3/01.py @@ -4,16 +4,15 @@ def lengthOfLongestSubstring(self, s: str) -> int: char_set = set() left = 0 res = 0 - + for right in range(len(s)): # If character already in window, shrink from left while s[right] in char_set: char_set.remove(s[left]) left += 1 - + # Add current character and update max length char_set.add(s[right]) res = max(res, right - left + 1) - - return res + return res diff --git a/solutions/30/01.py b/solutions/30/01.py index bd6032d..4c6a89c 100644 --- a/solutions/30/01.py +++ b/solutions/30/01.py @@ -1,45 +1,45 @@ from typing import List + class Solution: def findSubstring(self, s: str, words: List[str]) -> List[int]: if not s or not words: return [] - + word_len = len(words[0]) total_len = len(words) * word_len word_count = {} - + # Count frequency of each word for word in words: word_count[word] = word_count.get(word, 0) + 1 - + res = [] - + # Try each starting position for i in range(len(s) - total_len + 1): seen = {} j = 0 - + # Check if substring matches all words while j < len(words): start_idx = i + j * word_len - word = s[start_idx:start_idx + word_len] - + word = s[start_idx : start_idx + word_len] + # If word not in words or seen too many times if word not in word_count: break - + seen[word] = seen.get(word, 0) + 1 - + # If we've seen this word more times than available if seen[word] > word_count[word]: break - + j += 1 - + # If we matched all words if j == len(words): res.append(i) - - return res + return res diff --git a/solutions/300/01.py b/solutions/300/01.py index 82fdd2f..149ddd8 100644 --- a/solutions/300/01.py +++ b/solutions/300/01.py @@ -3,12 +3,11 @@ def lengthOfLIS(self, nums: List[int]) -> int: # Dynamic programming approach n = len(nums) dp = [1] * n - + for i in range(1, n): for j in range(i): if nums[j] < nums[i]: dp[i] = max(dp[i], dp[j] + 1) - + res = max(dp) return res - diff --git a/solutions/3110/01.py b/solutions/3110/01.py index 942b3f8..3401da8 100644 --- a/solutions/3110/01.py +++ b/solutions/3110/01.py @@ -4,4 +4,3 @@ def scoreOfString(self, s: str) -> int: for i in range(len(s) - 1): res += abs(ord(s[i]) - ord(s[i + 1])) return res - diff --git a/solutions/3178/01.py b/solutions/3178/01.py index fe2037e..0ff9a6a 100644 --- a/solutions/3178/01.py +++ b/solutions/3178/01.py @@ -4,16 +4,15 @@ def numberOfChild(self, n: int, k: int) -> int: # After this period, we're back to child 0 going right period = 2 * (n - 1) k_mod = k % period - + # Simulate the movement pos = 0 direction = 1 # 1 for right, -1 for left - + for _ in range(k_mod): pos += direction # Reverse direction at boundaries if pos == 0 or pos == n - 1: direction = -direction - - return pos + return pos diff --git a/solutions/3179/01.py b/solutions/3179/01.py index bacba5a..d996548 100644 --- a/solutions/3179/01.py +++ b/solutions/3179/01.py @@ -3,11 +3,10 @@ def valueAfterKSeconds(self, n: int, k: int) -> int: MOD = 10**9 + 7 # Start with array of all 1s arr = [1] * n - + # Apply prefix sum k times for _ in range(k): for i in range(1, n): arr[i] = (arr[i] + arr[i - 1]) % MOD - - return arr[n - 1] + return arr[n - 1] diff --git a/solutions/3190/01.py b/solutions/3190/01.py index 372f83c..ece07fe 100644 --- a/solutions/3190/01.py +++ b/solutions/3190/01.py @@ -8,4 +8,3 @@ def minimumOperations(self, nums: List[int]) -> int: # Choose the minimum operations (always 1) res += min(remainder, 3 - remainder) return res - diff --git a/solutions/3212/01.py b/solutions/3212/01.py index d723f44..d78f1ea 100644 --- a/solutions/3212/01.py +++ b/solutions/3212/01.py @@ -1,21 +1,23 @@ class Solution: def numberOfSubmatrices(self, grid: List[List[str]]) -> int: m, n = len(grid), len(grid[0]) - + # Convert to numeric values: X=1, Y=-1, .=0 # Build prefix sum matrix prefix = [[0] * (n + 1) for _ in range(m + 1)] - + for i in range(m): for j in range(n): val = 0 - if grid[i][j] == 'X': + if grid[i][j] == "X": val = 1 - elif grid[i][j] == 'Y': + elif grid[i][j] == "Y": val = -1 - - prefix[i + 1][j + 1] = val + prefix[i][j + 1] + prefix[i + 1][j] - prefix[i][j] - + + prefix[i + 1][j + 1] = ( + val + prefix[i][j + 1] + prefix[i + 1][j] - prefix[i][j] + ) + res = 0 # Check all submatrices starting from (0,0) for i in range(m): @@ -24,19 +26,18 @@ def numberOfSubmatrices(self, grid: List[List[str]]) -> int: has_x = False for x in range(i + 1): for y in range(j + 1): - if grid[x][y] == 'X': + if grid[x][y] == "X": has_x = True break if has_x: break - + if not has_x: continue - + # Calculate sum of submatrix from (0,0) to (i,j) # Using prefix sum: sum = prefix[i+1][j+1] if prefix[i + 1][j + 1] == 0: res += 1 - - return res + return res diff --git a/solutions/3213/01.py b/solutions/3213/01.py index 0bf2c1c..62e4729 100644 --- a/solutions/3213/01.py +++ b/solutions/3213/01.py @@ -2,18 +2,17 @@ class Solution: def minimumCost(self, target: str, words: List[str], costs: List[int]) -> int: n = len(target) # dp[i] = minimum cost to construct target[0:i] - dp = [float('inf')] * (n + 1) + dp = [float("inf")] * (n + 1) dp[0] = 0 - + for i in range(n): - if dp[i] == float('inf'): + if dp[i] == float("inf"): continue - + # Try each word for j, word in enumerate(words): word_len = len(word) - if i + word_len <= n and target[i:i + word_len] == word: + if i + word_len <= n and target[i : i + word_len] == word: dp[i + word_len] = min(dp[i + word_len], dp[i] + costs[j]) - - return dp[n] if dp[n] != float('inf') else -1 + return dp[n] if dp[n] != float("inf") else -1 diff --git a/solutions/322/01.py b/solutions/322/01.py index da60fd2..15b41bb 100644 --- a/solutions/322/01.py +++ b/solutions/322/01.py @@ -1,14 +1,13 @@ class Solution: def coinChange(self, coins: List[int], amount: int) -> int: # Dynamic programming: dp[i] = minimum coins needed for amount i - dp = [float('inf')] * (amount + 1) + dp = [float("inf")] * (amount + 1) dp[0] = 0 - + for i in range(1, amount + 1): for coin in coins: if i >= coin: dp[i] = min(dp[i], dp[i - coin] + 1) - - res = dp[amount] if dp[amount] != float('inf') else -1 - return res + res = dp[amount] if dp[amount] != float("inf") else -1 + return res diff --git a/solutions/3260/01.py b/solutions/3260/01.py index 5efd810..604ef46 100644 --- a/solutions/3260/01.py +++ b/solutions/3260/01.py @@ -2,25 +2,25 @@ class Solution: def largestPalindrome(self, n: int, k: int) -> str: # For very large n, use optimized construction # Build palindrome digit by digit, only keeping best per remainder - + # dp[rem] = tuple of digits (first half only) dp = {0: ()} - + half = (n + 1) // 2 - + for pos in range(half): new_dp = {} - + for rem, digits in dp.items(): # Try digits 9 down to 0, but stop early if we find a solution found_solution = False - + for digit in range(9, -1, -1): if pos == 0 and digit == 0: continue - + mirror_pos = n - 1 - pos - + # Calculate new remainder if pos == mirror_pos: power = pow(10, pos, k) @@ -29,44 +29,44 @@ def largestPalindrome(self, n: int, k: int) -> str: left_power = pow(10, pos, k) right_power = pow(10, mirror_pos, k) new_rem = (rem + digit * (left_power + right_power)) % k - + new_digits = digits + (digit,) - + # Keep best for this remainder if new_rem not in new_dp or new_digits > new_dp[new_rem]: new_dp[new_rem] = new_digits - + # Early check: if this is the last position and remainder is 0, we're done if pos == half - 1 and new_rem == 0: found_solution = True # Reconstruct and return immediately - pal_list = [''] * n + pal_list = [""] * n for i, d in enumerate(new_digits): pal_list[i] = str(d) if i != n - 1 - i: pal_list[n - 1 - i] = str(d) - res = ''.join(pal_list) - if len(res) == n and res[0] != '0': + res = "".join(pal_list) + if len(res) == n and res[0] != "0": return res - + # If we found a solution, we can break early if found_solution: break - + dp = new_dp # Limit states: only keep best candidate per remainder # This prevents explosion of states - + # Final reconstruction if 0 in dp: digits = dp[0] - pal_list = [''] * n + pal_list = [""] * n for i, d in enumerate(digits): pal_list[i] = str(d) if i != n - 1 - i: pal_list[n - 1 - i] = str(d) - res = ''.join(pal_list) - if len(res) == n and res[0] != '0': + res = "".join(pal_list) + if len(res) == n and res[0] != "0": return res - + return str(k) * n diff --git a/solutions/3271/01.py b/solutions/3271/01.py index f445439..d65743b 100644 --- a/solutions/3271/01.py +++ b/solutions/3271/01.py @@ -4,7 +4,7 @@ def stringHash(self, s: str, k: int) -> str: res = [] for i in range(0, len(s), k): chunk = s[i : i + k] - total = sum(ord(c) - ord('a') for c in chunk) + total = sum(ord(c) - ord("a") for c in chunk) hashed = total % 26 - res.append(chr(ord('a') + hashed)) - return ''.join(res) + res.append(chr(ord("a") + hashed)) + return "".join(res) diff --git a/solutions/328/01.py b/solutions/328/01.py index 627f5b6..45b458f 100644 --- a/solutions/328/01.py +++ b/solutions/328/01.py @@ -7,17 +7,16 @@ class Solution: def oddEvenList(self, head: Optional[ListNode]) -> Optional[ListNode]: if not head or not head.next: return head - + odd = head even = head.next even_head = even - + while even and even.next: odd.next = even.next odd = odd.next even.next = odd.next even = even.next - + odd.next = even_head return head - diff --git a/solutions/33/01.py b/solutions/33/01.py index fc61629..b136d19 100644 --- a/solutions/33/01.py +++ b/solutions/33/01.py @@ -1,15 +1,16 @@ from typing import List + class Solution: def search(self, nums: List[int], target: int) -> int: left, right = 0, len(nums) - 1 - + while left <= right: mid = (left + right) // 2 - + if nums[mid] == target: return mid - + # Left half is sorted if nums[left] <= nums[mid]: if nums[left] <= target < nums[mid]: @@ -22,6 +23,5 @@ def search(self, nums: List[int], target: int) -> int: left = mid + 1 else: right = mid - 1 - - return -1 + return -1 diff --git a/solutions/334/01.py b/solutions/334/01.py index c348063..61d749a 100644 --- a/solutions/334/01.py +++ b/solutions/334/01.py @@ -1,10 +1,11 @@ from typing import List + class Solution: def increasingTriplet(self, nums: List[int]) -> bool: - first = float('inf') - second = float('inf') - + first = float("inf") + second = float("inf") + for num in nums: if num <= first: first = num @@ -13,5 +14,5 @@ def increasingTriplet(self, nums: List[int]) -> bool: else: # Found a number greater than both first and second return True - + return False diff --git a/solutions/337/01.py b/solutions/337/01.py index ff45b38..d154e2d 100644 --- a/solutions/337/01.py +++ b/solutions/337/01.py @@ -9,17 +9,16 @@ def rob(self, root: Optional[TreeNode]) -> int: def dfs(node): if not node: return (0, 0) # (rob this node, don't rob this node) - + left = dfs(node.left) right = dfs(node.right) - + # If we rob this node, we can't rob children rob_this = node.val + left[1] + right[1] - + # If we don't rob this node, we can choose to rob or not rob children dont_rob_this = max(left) + max(right) - + return (rob_this, dont_rob_this) - - return max(dfs(root)) + return max(dfs(root)) diff --git a/solutions/338/01.py b/solutions/338/01.py index 328be26..08e9141 100644 --- a/solutions/338/01.py +++ b/solutions/338/01.py @@ -1,12 +1,12 @@ from typing import List + class Solution: def countBits(self, n: int) -> List[int]: res = [0] * (n + 1) - + for i in range(1, n + 1): # Number of 1s in i is same as i//2, plus 1 if i is odd res[i] = res[i // 2] + (i % 2) - - return res + return res diff --git a/solutions/3381/01.py b/solutions/3381/01.py index d5a4ecc..5e3db3e 100644 --- a/solutions/3381/01.py +++ b/solutions/3381/01.py @@ -1,25 +1,26 @@ from typing import List + class Solution: def maxSubarraySum(self, nums: List[int], k: int) -> int: n = len(nums) - + # Calculate prefix sums: prefix[i] = sum of nums[0..i-1] prefix = [0] * (n + 1) for i in range(n): prefix[i + 1] = prefix[i] + nums[i] - + # Track minimum prefix sum for each residue class (index % k) # min_prefix[r] = minimum prefix sum at position i where i % k == r # Initialize with prefix[0] = 0 for residue 0 min_prefix = {0: prefix[0]} - - res = float('-inf') - + + res = float("-inf") + # For each position i (1 to n), check valid subarrays ending at i-1 for i in range(1, n + 1): r = i % k # residue class - + # First, check if we can form a valid subarray using previous minimum if r in min_prefix: # Calculate sum: prefix[i] - min_prefix[r] @@ -29,11 +30,11 @@ def maxSubarraySum(self, nums: List[int], k: int) -> int: # their difference is divisible by k current_sum = prefix[i] - min_prefix[r] res = max(res, current_sum) - + # Then update minimum prefix sum for this residue class if r not in min_prefix: min_prefix[r] = prefix[i] else: min_prefix[r] = min(min_prefix[r], prefix[i]) - + return res diff --git a/solutions/34/01.py b/solutions/34/01.py index 0db54ae..4513f3b 100644 --- a/solutions/34/01.py +++ b/solutions/34/01.py @@ -1,11 +1,12 @@ from typing import List + class Solution: def searchRange(self, nums: List[int], target: int) -> List[int]: def find_first(nums, target): left, right = 0, len(nums) - 1 first = -1 - + while left <= right: mid = (left + right) // 2 if nums[mid] == target: @@ -15,13 +16,13 @@ def find_first(nums, target): left = mid + 1 else: right = mid - 1 - + return first - + def find_last(nums, target): left, right = 0, len(nums) - 1 last = -1 - + while left <= right: mid = (left + right) // 2 if nums[mid] == target: @@ -31,13 +32,12 @@ def find_last(nums, target): left = mid + 1 else: right = mid - 1 - + return last - + first = find_first(nums, target) if first == -1: return [-1, -1] - + last = find_last(nums, target) return [first, last] - diff --git a/solutions/3432/01.py b/solutions/3432/01.py index 2b822b8..2f8fd50 100644 --- a/solutions/3432/01.py +++ b/solutions/3432/01.py @@ -2,26 +2,27 @@ class Solution: def resultsArray(self, nums: List[int], k: int) -> List[int]: n = len(nums) res = [] - + for i in range(n - k + 1): # Extract subarray of size k - subarray = nums[i:i+k] - + subarray = nums[i : i + k] + # Check if all elements are consecutive and sorted # First, check if sorted in ascending order - is_sorted = all(subarray[j] <= subarray[j+1] for j in range(k-1)) - + is_sorted = all(subarray[j] <= subarray[j + 1] for j in range(k - 1)) + if not is_sorted: res.append(-1) continue - + # Check if consecutive - is_consecutive = all(subarray[j] + 1 == subarray[j+1] for j in range(k-1)) - + is_consecutive = all( + subarray[j] + 1 == subarray[j + 1] for j in range(k - 1) + ) + if is_consecutive: res.append(max(subarray)) else: res.append(-1) - - return res + return res diff --git a/solutions/345/01.py b/solutions/345/01.py index ec87115..8cfb44a 100644 --- a/solutions/345/01.py +++ b/solutions/345/01.py @@ -1,10 +1,10 @@ class Solution: def reverseVowels(self, s: str) -> str: - vowels = set('aeiouAEIOU') + vowels = set("aeiouAEIOU") s_list = list(s) left = 0 right = len(s_list) - 1 - + while left < right: # Find vowel from left while left < right and s_list[left] not in vowels: @@ -12,10 +12,10 @@ def reverseVowels(self, s: str) -> str: # Find vowel from right while left < right and s_list[right] not in vowels: right -= 1 - + # Swap vowels s_list[left], s_list[right] = s_list[right], s_list[left] left += 1 right -= 1 - - return ''.join(s_list) + + return "".join(s_list) diff --git a/solutions/347/01.py b/solutions/347/01.py index 07c7e78..88c50a4 100644 --- a/solutions/347/01.py +++ b/solutions/347/01.py @@ -4,12 +4,12 @@ def topKFrequent(self, nums: List[int], k: int) -> List[int]: count = {} for num in nums: count[num] = count.get(num, 0) + 1 - + # Create buckets: index = frequency, value = list of numbers buckets = [[] for _ in range(len(nums) + 1)] for num, freq in count.items(): buckets[freq].append(num) - + # Collect top k frequent elements res = [] for i in range(len(buckets) - 1, -1, -1): @@ -17,6 +17,5 @@ def topKFrequent(self, nums: List[int], k: int) -> List[int]: res.append(num) if len(res) == k: return res - - return res + return res diff --git a/solutions/3512/01.py b/solutions/3512/01.py index 43acfde..30e3bae 100644 --- a/solutions/3512/01.py +++ b/solutions/3512/01.py @@ -2,22 +2,21 @@ class Solution: def resultsArray(self, nums: List[int], k: int) -> List[int]: n = len(nums) res = [] - + for i in range(n - k + 1): - subarray = nums[i:i + k] + subarray = nums[i : i + k] # Check if all elements are consecutive and sorted sorted_sub = sorted(subarray) is_consecutive = True - + for j in range(k - 1): if sorted_sub[j + 1] - sorted_sub[j] != 1: is_consecutive = False break - + if is_consecutive and subarray == sorted_sub: res.append(max(subarray)) else: res.append(-1) - - return res + return res diff --git a/solutions/3522/01.py b/solutions/3522/01.py index 0563d2a..aabf4f4 100644 --- a/solutions/3522/01.py +++ b/solutions/3522/01.py @@ -2,14 +2,14 @@ class Solution: def resultsArray(self, nums: List[int], k: int) -> List[int]: n = len(nums) res = [] - + for i in range(n - k + 1): - subarray = nums[i:i + k] + subarray = nums[i : i + k] # Check if all elements are consecutive and sorted expected = list(range(subarray[0], subarray[0] + k)) if subarray == expected: res.append(max(subarray)) else: res.append(-1) - + return res diff --git a/solutions/3562/01.py b/solutions/3562/01.py index 5c4f279..4d0885d 100644 --- a/solutions/3562/01.py +++ b/solutions/3562/01.py @@ -1,33 +1,44 @@ class Solution: - def maxProfit(self, n: int, present: List[int], future: List[int], hierarchy: List[List[int]], budget: int) -> int: + def maxProfit( + self, + n: int, + present: List[int], + future: List[int], + hierarchy: List[List[int]], + budget: int, + ) -> int: from collections import defaultdict from functools import lru_cache - + # Build adjacency list (0-indexed) adj_list = defaultdict(list) for u, v in hierarchy: adj_list[u - 1].append(v - 1) - + @lru_cache(maxsize=None) def dfs(employee, has_discount): # Calculate cost and profit for current employee cost = present[employee] // 2 if has_discount else present[employee] profit = future[employee] - cost - + # Option 1: Buy current stock buy_current = {} if cost <= budget: buy_current[cost] = profit - + # Option 2: Skip current stock skip_current = {0: 0} - + # Process children using knapsack approach for child in adj_list[employee]: # Get child results with and without discount - child_with_discount = dfs(child, True) # If we buy current, child gets discount - child_no_discount = dfs(child, False) # If we skip current, child has no discount - + child_with_discount = dfs( + child, True + ) # If we buy current, child gets discount + child_no_discount = dfs( + child, False + ) # If we skip current, child has no discount + # Merge buy_current with child results new_buy = {} for spent, prof in buy_current.items(): @@ -35,10 +46,13 @@ def dfs(employee, has_discount): total_spent = spent + child_spent if total_spent <= budget: total_prof = prof + child_prof - if total_spent not in new_buy or new_buy[total_spent] < total_prof: + if ( + total_spent not in new_buy + or new_buy[total_spent] < total_prof + ): new_buy[total_spent] = total_prof buy_current = new_buy - + # Merge skip_current with child results new_skip = {} for spent, prof in skip_current.items(): @@ -46,10 +60,13 @@ def dfs(employee, has_discount): total_spent = spent + child_spent if total_spent <= budget: total_prof = prof + child_prof - if total_spent not in new_skip or new_skip[total_spent] < total_prof: + if ( + total_spent not in new_skip + or new_skip[total_spent] < total_prof + ): new_skip[total_spent] = total_prof skip_current = new_skip - + # Merge buy and skip results result = {} for spent, prof in buy_current.items(): @@ -58,9 +75,8 @@ def dfs(employee, has_discount): for spent, prof in skip_current.items(): if spent not in result or result[spent] < prof: result[spent] = prof - + return result - + result = dfs(0, False) # Root has no parent, so no discount return max(result.values()) if result else 0 - diff --git a/solutions/3573/01.py b/solutions/3573/01.py index 23c0646..a9e78d3 100644 --- a/solutions/3573/01.py +++ b/solutions/3573/01.py @@ -4,11 +4,11 @@ def maximumProfit(self, prices: List[int], k: int) -> int: res = [0] * (k + 1) # bought[j] - best profit if holding a "bought" position in j-th transaction # (bought normally, waiting to sell) - bought = [-float('inf')] * k + bought = [-float("inf")] * k # sold[j] - best profit if holding a "short sold" position in j-th transaction # (sold short, waiting to buy back) sold = [0] * k - + for price in prices: # Process from k down to 1 to avoid using updated values for j in range(k, 0, -1): @@ -16,12 +16,11 @@ def maximumProfit(self, prices: List[int], k: int) -> int: # - Complete normal: sell at current price (bought[j-1] + price) # - Complete short: buy back at current price (sold[j-1] - price) res[j] = max(res[j], bought[j - 1] + price, sold[j - 1] - price) - + # Start a new transaction: # - Start normal: buy at current price (res[j-1] - price) bought[j - 1] = max(bought[j - 1], res[j - 1] - price) # - Start short: sell at current price (res[j-1] + price) sold[j - 1] = max(sold[j - 1], res[j - 1] + price) - - return max(res) + return max(res) diff --git a/solutions/3583/01.py b/solutions/3583/01.py index ab7676b..6fdd23e 100644 --- a/solutions/3583/01.py +++ b/solutions/3583/01.py @@ -2,41 +2,40 @@ class Solution: def specialTriplets(self, nums: List[int]) -> int: n = len(nums) MOD = 10**9 + 7 - + # For each j, count how many i < j have nums[i] == nums[j] * 2 # and how many k > j have nums[k] == nums[j] * 2 res = 0 - + # Count frequencies before current position freq_before = {} # Count frequencies after current position freq_after = {} - + # Initialize freq_after with all elements for num in nums: freq_after[num] = freq_after.get(num, 0) + 1 - + # Process each j for j in range(n): # Remove current element from freq_after freq_after[nums[j]] -= 1 if freq_after[nums[j]] == 0: del freq_after[nums[j]] - + # Calculate target value: nums[j] * 2 target = nums[j] * 2 - + # Count i < j with nums[i] == target count_before = freq_before.get(target, 0) - + # Count k > j with nums[k] == target count_after = freq_after.get(target, 0) - + # Add to result res = (res + count_before * count_after) % MOD - + # Add current element to freq_before freq_before[nums[j]] = freq_before.get(nums[j], 0) + 1 - - return res + return res diff --git a/solutions/3602/01.py b/solutions/3602/01.py index b090ffa..3b9ec72 100644 --- a/solutions/3602/01.py +++ b/solutions/3602/01.py @@ -1,9 +1,9 @@ def concatHex36(n: int) -> str: n2 = n * n n3 = n * n * n - hex_part = format(n2, 'X') - base36_chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' - base36_part = '' + hex_part = format(n2, "X") + base36_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + base36_part = "" num = n3 while num > 0: # Find the remainder when num is divided by 36, @@ -11,4 +11,4 @@ def concatHex36(n: int) -> str: # and prepend it to base36_part. base36_part = base36_chars[num % 36] + base36_part num //= 36 - return hex_part + base36_part \ No newline at end of file + return hex_part + base36_part diff --git a/solutions/3606/01.py b/solutions/3606/01.py index 5164463..83723fc 100644 --- a/solutions/3606/01.py +++ b/solutions/3606/01.py @@ -1,31 +1,34 @@ from typing import List + class Solution: - def validateCoupons(self, code: List[str], businessLine: List[str], isActive: List[bool]) -> List[str]: + def validateCoupons( + self, code: List[str], businessLine: List[str], isActive: List[bool] + ) -> List[str]: # Valid business lines in priority order valid_business_lines = ["electronics", "grocery", "pharmacy", "restaurant"] priority = {line: i for i, line in enumerate(valid_business_lines)} - + res = [] - + for i in range(len(code)): # Check if coupon is active if not isActive[i]: continue - + # Check if code is non-empty and contains only alphanumeric and underscore - if not code[i] or not all(c.isalnum() or c == '_' for c in code[i]): + if not code[i] or not all(c.isalnum() or c == "_" for c in code[i]): continue - + # Check if business line is valid if businessLine[i] not in priority: continue - + # Coupon is valid, add to result with priority info for sorting res.append((priority[businessLine[i]], code[i])) - + # Sort by business line priority, then by code lexicographically res.sort() - + # Return only the codes return [code for _, code in res] diff --git a/solutions/3625/01.py b/solutions/3625/01.py index 724919e..b0c1324 100644 --- a/solutions/3625/01.py +++ b/solutions/3625/01.py @@ -1,6 +1,7 @@ from typing import List from collections import defaultdict + class Solution: def countTrapezoids(self, points: List[List[int]]) -> int: n = len(points) @@ -8,7 +9,7 @@ def countTrapezoids(self, points: List[List[int]]) -> int: slope_to_intercept = defaultdict(list) mid_to_slope = defaultdict(list) res = 0 - + # Process all pairs of points for i in range(n): x1, y1 = points[i] @@ -16,7 +17,7 @@ def countTrapezoids(self, points: List[List[int]]) -> int: x2, y2 = points[j] dx = x1 - x2 dy = y1 - y2 - + # Calculate slope and intercept if x2 == x1: # Vertical line: infinite slope, use x-coordinate as intercept @@ -25,42 +26,41 @@ def countTrapezoids(self, points: List[List[int]]) -> int: else: k = (y2 - y1) / (x2 - x1) b = (y1 * dx - x1 * dy) / dx - + # Store midpoint as single integer: (x1+x2)*10000 + (y1+y2) mid = (x1 + x2) * 10000 + (y1 + y2) - + slope_to_intercept[k].append(b) mid_to_slope[mid].append(k) - + # Count trapezoids: for each slope, count pairs of segments with same slope for intercepts in slope_to_intercept.values(): if len(intercepts) == 1: continue - + cnt = defaultdict(int) for b_val in intercepts: cnt[b_val] += 1 - + # Count pairs: for each intercept count, multiply with previous total total_sum = 0 for count in cnt.values(): res += total_sum * count total_sum += count - + # Subtract parallelograms: segments with same midpoint but different slopes for slopes in mid_to_slope.values(): if len(slopes) == 1: continue - + cnt = defaultdict(int) for k_val in slopes: cnt[k_val] += 1 - + # Subtract pairs of different slopes at same midpoint total_sum = 0 for count in cnt.values(): res -= total_sum * count total_sum += count - - return res + return res diff --git a/solutions/3644/01.py b/solutions/3644/01.py index e7002b1..409176a 100644 --- a/solutions/3644/01.py +++ b/solutions/3644/01.py @@ -7,4 +7,3 @@ def sortPermutation(self, nums: List[int]) -> int: mask &= val # If mask unchanged (no mismatches), return 0 return 0 if mask == (1 << 30) - 1 else mask - diff --git a/solutions/3645/01.py b/solutions/3645/01.py index 09291ed..a6599b6 100644 --- a/solutions/3645/01.py +++ b/solutions/3645/01.py @@ -2,15 +2,15 @@ class Solution: def maxTotal(self, value: List[int], limit: List[int]) -> int: from collections import defaultdict import heapq - + # Group items by their limit values groups = defaultdict(list) for i, (v, l) in enumerate(zip(value, limit)): groups[l].append(v) - + res = 0 active_count = 0 - + # Process groups in order of limit (smallest first) for limit_val in sorted(groups.keys()): # Use min-heap to keep top min(limit_val, len(group)) values @@ -19,10 +19,9 @@ def maxTotal(self, value: List[int], limit: List[int]) -> int: heapq.heappush(heap, v) if len(heap) > limit_val: heapq.heappop(heap) - + # Sum all values in heap and add to result res += sum(heap) active_count += len(heap) - - return res + return res diff --git a/solutions/3648/01.py b/solutions/3648/01.py index 943de49..4aadad7 100644 --- a/solutions/3648/01.py +++ b/solutions/3648/01.py @@ -4,4 +4,3 @@ def minSensors(self, n: int, m: int, k: int) -> int: x = (n + size - 1) // size # ceil(n / size) y = (m + size - 1) // size # ceil(m / size) return x * y - diff --git a/solutions/3649/01.py b/solutions/3649/01.py index 9d83359..2eb6d92 100644 --- a/solutions/3649/01.py +++ b/solutions/3649/01.py @@ -2,10 +2,10 @@ class Solution: def perfectPairs(self, nums: List[int]) -> int: # Work with absolute values and sort arr = sorted(abs(x) for x in nums) - + res = 0 j = 1 - + # For each i, find the rightmost j such that arr[j] <= 2 * arr[i] for i in range(len(arr)): # Ensure j > i @@ -17,4 +17,3 @@ def perfectPairs(self, nums: List[int]) -> int: # Count pairs: all indices between i+1 and j-1 form valid pairs with i # j points to first element > 2*arr[i], so valid pairs are from i+1 to j-1 res += max(0, j - i - 1) - diff --git a/solutions/3652/01.py b/solutions/3652/01.py index 2cb9783..1eabb67 100644 --- a/solutions/3652/01.py +++ b/solutions/3652/01.py @@ -1,35 +1,38 @@ class Solution: def maxProfit(self, prices: List[int], strategy: List[int], k: int) -> int: n = len(prices) - + # Calculate base profit without modification base_profit = sum(strategy[i] * prices[i] for i in range(n)) - + # Precompute prefix sums for prices price_prefix = [0] * (n + 1) for i in range(n): price_prefix[i + 1] = price_prefix[i] + prices[i] - + # Precompute prefix sums for strategy * prices (original profit) strategy_profit_prefix = [0] * (n + 1) for i in range(n): - strategy_profit_prefix[i + 1] = strategy_profit_prefix[i] + strategy[i] * prices[i] - + strategy_profit_prefix[i + 1] = ( + strategy_profit_prefix[i] + strategy[i] * prices[i] + ) + res = base_profit - + # Try each possible segment [i, i+k-1] for i in range(n - k + 1): # Original profit from this segment using prefix sum - original_segment_profit = strategy_profit_prefix[i + k] - strategy_profit_prefix[i] - + original_segment_profit = ( + strategy_profit_prefix[i + k] - strategy_profit_prefix[i] + ) + # Modified segment: first k/2 are 0 (hold), last k/2 are 1 (sell) # Profit from modified segment = sum of prices in last k/2 modified_segment_profit = price_prefix[i + k] - price_prefix[i + k // 2] - + # Delta = modified - original delta = modified_segment_profit - original_segment_profit - + res = max(res, base_profit + delta) - - return res + return res diff --git a/solutions/3653/01.py b/solutions/3653/01.py index c47a2ce..c974852 100644 --- a/solutions/3653/01.py +++ b/solutions/3653/01.py @@ -1,17 +1,16 @@ class Solution: def xorAfterQueries(self, nums: List[int], queries: List[List[int]]) -> int: MOD = 10**9 + 7 - + # Apply each query for l, r, k, v in queries: idx = l while idx <= r: nums[idx] = (nums[idx] * v) % MOD idx += k - + # Calculate XOR of all elements res = 0 for num in nums: res ^= num return res - diff --git a/solutions/3663/01.py b/solutions/3663/01.py index 6960360..ec72487 100644 --- a/solutions/3663/01.py +++ b/solutions/3663/01.py @@ -2,16 +2,17 @@ class Solution: def getLeastFrequentDigit(self, n: int) -> int: # Convert n to string to iterate through digits s = str(n) - + # Count frequency of each digit freq = {} for digit in s: freq[digit] = freq.get(digit, 0) + 1 - + # Find the minimum frequency min_freq = min(freq.values()) - + # Find all digits with minimum frequency and return the smallest - least_frequent_digits = [int(d) for d, count in freq.items() if count == min_freq] + least_frequent_digits = [ + int(d) for d, count in freq.items() if count == min_freq + ] return min(least_frequent_digits) - diff --git a/solutions/3668/01.py b/solutions/3668/01.py index fe0085d..1a76437 100644 --- a/solutions/3668/01.py +++ b/solutions/3668/01.py @@ -3,11 +3,10 @@ def recoverOrder(self, order: List[int], friends: List[int]) -> List[int]: # Create a set for O(1) lookup friend_set = set(friends) res = [] - + # Iterate through order and collect friends in their finishing order for num in order: if num in friend_set: res.append(num) - - return res + return res diff --git a/solutions/3669/01.py b/solutions/3669/01.py index 4ebcd95..65eb46a 100644 --- a/solutions/3669/01.py +++ b/solutions/3669/01.py @@ -10,13 +10,13 @@ def minDifference(self, n: int, k: int) -> List[int]: divisors.append(n // i) i += 1 divisors.sort() - + res = None - min_diff = float('inf') - + min_diff = float("inf") + def dfs(start, picked, prod, path): nonlocal res, min_diff - + if picked == k: if prod == n: diff = max(path) - min(path) @@ -24,10 +24,10 @@ def dfs(start, picked, prod, path): min_diff = diff res = path[:] return - + if prod > n: return - + for i in range(start, len(divisors)): divisor = divisors[i] if prod * divisor > n: @@ -35,7 +35,6 @@ def dfs(start, picked, prod, path): path.append(divisor) dfs(i, picked + 1, prod * divisor, path) path.pop() - + dfs(0, 0, 1, []) return res - diff --git a/solutions/3675/01.py b/solutions/3675/01.py index 14325d8..e62641f 100644 --- a/solutions/3675/01.py +++ b/solutions/3675/01.py @@ -4,6 +4,5 @@ def minOperations(self, s: str) -> int: # Distance from 'a' in circular alphabet: (ord('a') + 26 - ord(c)) % 26 res = 0 for c in s: - res = max(res, (ord('a') + 26 - ord(c)) % 26) + res = max(res, (ord("a") + 26 - ord(c)) % 26) return res - diff --git a/solutions/3676/01.py b/solutions/3676/01.py index 7f0c777..390544a 100644 --- a/solutions/3676/01.py +++ b/solutions/3676/01.py @@ -2,19 +2,18 @@ class Solution: def bowlSubarrays(self, nums: List[int]) -> int: res = 0 stack = [] - + for r, val in enumerate(nums): # Pop elements that are <= current (they can form bowls with current) while stack and nums[stack[-1]] <= val: l = stack.pop() if r - l + 1 >= 3: res += 1 - + # Check if current element forms a bowl with stack top if stack and r - stack[-1] + 1 >= 3: res += 1 - + stack.append(r) - - return res + return res diff --git a/solutions/3678/01.py b/solutions/3678/01.py index dbe9e73..926d188 100644 --- a/solutions/3678/01.py +++ b/solutions/3678/01.py @@ -1,25 +1,25 @@ from typing import List + class Solution: def smallestAbsent(self, nums: List[int]) -> int: # Calculate the average average = sum(nums) / len(nums) - + # Convert nums to a set for O(1) lookup nums_set = set(nums) - + # Start from the smallest integer greater than the average # If average is 4.5, we want 5 (floor(4.5) + 1 = 5) # If average is 4.0, we want 5 (floor(4.0) + 1 = 5) res = int(average) + 1 - + # If average is negative or zero, we need to start from 1 (smallest positive) if res < 1: res = 1 - + # Increment res until we find a positive integer that is not in the array while res in nums_set: res += 1 - - return res + return res diff --git a/solutions/3679/01.py b/solutions/3679/01.py index 7ae8165..1c1443d 100644 --- a/solutions/3679/01.py +++ b/solutions/3679/01.py @@ -3,20 +3,19 @@ def minArrivalsToDiscard(self, arrivals: List[int], w: int, m: int) -> int: mx = max(arrivals) if arrivals else 0 ctr = [0] * (mx + 1) res = 0 - + for idx, item in enumerate(arrivals): # Remove item that left the window if idx >= w: left_item = arrivals[idx - w] if left_item != 0: # Only decrement if it was kept ctr[left_item] -= 1 - + # Check if we need to discard if ctr[item] >= m: res += 1 arrivals[idx] = 0 # Mark as discarded else: ctr[item] += 1 - - return res + return res diff --git a/solutions/3680/01.py b/solutions/3680/01.py index b2832b2..8bdb4bb 100644 --- a/solutions/3680/01.py +++ b/solutions/3680/01.py @@ -28,7 +28,7 @@ def generateSchedule(self, n: int) -> List[List[int]]: start = res[-1][-1] - 1 for i in range(start, start + n): res.append([(i + diff) % n, i % n]) - + if n % 2 == 0: # Find pairs that are n/2 apart start = res[-1][0] - 1 diff --git a/solutions/3683/01.py b/solutions/3683/01.py index 4b3e13b..ebcb390 100644 --- a/solutions/3683/01.py +++ b/solutions/3683/01.py @@ -2,11 +2,10 @@ class Solution: def earliestTime(self, tasks: List[List[int]]) -> int: # Calculate finish time for each task: start_time + duration # Return the minimum finish time - res = float('inf') - + res = float("inf") + for start, duration in tasks: finish_time = start + duration res = min(res, finish_time) - - return res + return res diff --git a/solutions/3685/01.py b/solutions/3685/01.py index 02bfa96..7df27c9 100644 --- a/solutions/3685/01.py +++ b/solutions/3685/01.py @@ -1,18 +1,18 @@ class Solution: def subsequenceSumAfterCapping(self, nums: List[int], k: int) -> List[bool]: n = len(nums) - + # Sort in ascending order sorted_nums = sorted(nums) - + # Precompute subset-sum DP for all elements # dp[i][j] = can we achieve sum j using first i elements dp = [[False] * (k + 1) for _ in range(n + 1)] - + # Base case: sum 0 is always possible for i in range(n + 1): dp[i][0] = True - + # Fill DP table for i in range(1, n + 1): for j in range(1, k + 1): @@ -20,7 +20,7 @@ def subsequenceSumAfterCapping(self, nums: List[int], k: int) -> List[bool]: dp[i][j] = dp[i - 1][j - sorted_nums[i - 1]] or dp[i - 1][j] else: dp[i][j] = dp[i - 1][j] - + res = [] # For each cap value x from 1 to n for x in range(1, n + 1): @@ -30,14 +30,14 @@ def subsequenceSumAfterCapping(self, nums: List[int], k: int) -> List[bool]: if sorted_nums[i] > x: ind = i break - + # If no element > x, use original array result if ind == n: res.append(dp[n][k]) else: # Elements from ind to n-1 will be capped to x sz = n - ind # Number of elements that become x - + # Check if we can form sum k found = False for j in range(k + 1): @@ -49,6 +49,5 @@ def subsequenceSumAfterCapping(self, nums: List[int], k: int) -> List[bool]: found = True break res.append(found) - - return res + return res diff --git a/solutions/3688/01.py b/solutions/3688/01.py index aec3fef..e47d0a1 100644 --- a/solutions/3688/01.py +++ b/solutions/3688/01.py @@ -1,15 +1,15 @@ from typing import List + class Solution: def evenNumberBitwiseORs(self, nums: List[int]) -> int: result = 0 has_even = False - + for num in nums: if num % 2 == 0: # Even number: perform bitwise OR result |= num has_even = True - - return result if has_even else 0 + return result if has_even else 0 diff --git a/solutions/3689/01.py b/solutions/3689/01.py index 2f90259..0ef50b1 100644 --- a/solutions/3689/01.py +++ b/solutions/3689/01.py @@ -5,4 +5,3 @@ def maxTotalValue(self, nums: List[int], k: int) -> int: max_val = max(nums) min_val = min(nums) return (max_val - min_val) * k - diff --git a/solutions/3690/01.py b/solutions/3690/01.py index be4eb09..5809993 100644 --- a/solutions/3690/01.py +++ b/solutions/3690/01.py @@ -1,35 +1,34 @@ class Solution: def minSplitMerge(self, nums1: List[int], nums2: List[int]) -> int: from collections import deque - + # BFS to find minimum operations queue = deque([(tuple(nums1), 0)]) visited = {tuple(nums1)} target = tuple(nums2) - + while queue: state, ops = queue.popleft() - + if state == target: return ops - + # Try all possible split-and-merge operations n = len(state) for l in range(n): for r in range(l, n): # Remove subarray [l..r] - removed = state[l:r+1] + removed = state[l : r + 1] prefix = state[:l] - suffix = state[r+1:] - + suffix = state[r + 1 :] + # Try inserting at all possible positions for pos in range(len(prefix) + len(suffix) + 1): new_state = prefix[:pos] + removed + prefix[pos:] + suffix new_state_tuple = tuple(new_state) - + if new_state_tuple not in visited: visited.add(new_state_tuple) queue.append((new_state_tuple, ops + 1)) - - return -1 + return -1 diff --git a/solutions/3692/01.py b/solutions/3692/01.py index 204110a..3cc4349 100644 --- a/solutions/3692/01.py +++ b/solutions/3692/01.py @@ -1,30 +1,30 @@ from collections import defaultdict, Counter + class Solution: def majorityFrequencyGroup(self, s: str) -> str: # Count frequency of each character freq = Counter(s) - + # Group characters by their frequency # freq_group[k] = list of characters that appear exactly k times freq_group = defaultdict(list) for char, count in freq.items(): freq_group[count].append(char) - + # Find the majority frequency group # We want the group with: # 1. Largest number of distinct characters # 2. If tied, higher frequency value max_size = 0 best_freq = 0 - + for k, chars in freq_group.items(): size = len(chars) # If this group has more characters, or same size but higher frequency if size > max_size or (size == max_size and k > best_freq): max_size = size best_freq = k - - # Return all characters in the majority frequency group - return ''.join(freq_group[best_freq]) + # Return all characters in the majority frequency group + return "".join(freq_group[best_freq]) diff --git a/solutions/3693/01.py b/solutions/3693/01.py index 7962709..fc358fe 100644 --- a/solutions/3693/01.py +++ b/solutions/3693/01.py @@ -3,12 +3,11 @@ def climbStairs(self, n: int, costs: List[int]) -> int: # Use rolling array of size 3 to save space # dp[i] represents minimum cost to reach step i v0 = v1 = v2 = 0 - + for i, c in enumerate(costs): # From step i, we can reach step i+1, i+2, or i+3 # Cost = previous cost + jump cost (1, 4, or 9) + step cost v = min(v0 + 9, v1 + 4, v2 + 1) + c v0, v1, v2 = v1, v2, v - - return v2 + return v2 diff --git a/solutions/3694/01.py b/solutions/3694/01.py index 4a815ba..71883d5 100644 --- a/solutions/3694/01.py +++ b/solutions/3694/01.py @@ -2,31 +2,30 @@ class Solution: def distinctPoints(self, s: str, k: int) -> int: seen = {(0, 0)} x = y = 0 - + # Sliding window: simulate removing each substring of length k # Start by processing characters from k onwards for i in range(k, len(s)): # Add effect of new character at position i - if s[i] == 'U': + if s[i] == "U": y += 1 - elif s[i] == 'D': + elif s[i] == "D": y -= 1 - elif s[i] == 'L': + elif s[i] == "L": x -= 1 - elif s[i] == 'R': + elif s[i] == "R": x += 1 - + # Remove effect of character at position i - k (leaving the window) - if s[i - k] == 'U': + if s[i - k] == "U": y -= 1 - elif s[i - k] == 'D': + elif s[i - k] == "D": y += 1 - elif s[i - k] == 'L': + elif s[i - k] == "L": x += 1 - elif s[i - k] == 'R': + elif s[i - k] == "R": x -= 1 - + seen.add((x, y)) - - return len(seen) + return len(seen) diff --git a/solutions/3697/01.py b/solutions/3697/01.py index 0464e9e..9b3d3e5 100644 --- a/solutions/3697/01.py +++ b/solutions/3697/01.py @@ -1,11 +1,12 @@ from typing import List + class Solution: def decimalRepresentation(self, n: int) -> List[int]: # Convert to string to access digits s = str(n) components = [] - + # Process each digit from right to left (ones place to highest place) # We'll build components and then reverse to get descending order for i in range(len(s) - 1, -1, -1): @@ -14,9 +15,8 @@ def decimalRepresentation(self, n: int) -> List[int]: # Calculate the power of 10 for this position # Position 0 (rightmost) = 10^0, position 1 = 10^1, etc. power = len(s) - 1 - i - component = digit * (10 ** power) + component = digit * (10**power) components.append(component) - + # Return in descending order (largest to smallest) return components[::-1] - diff --git a/solutions/3698/01.py b/solutions/3698/01.py index 06afb18..a33a219 100644 --- a/solutions/3698/01.py +++ b/solutions/3698/01.py @@ -5,17 +5,17 @@ def splitArray(self, nums: List[int]) -> int: r = n - 1 lsum = 0 rsum = 0 - + # Strictly increasing from left while l < n - 1 and nums[l] < nums[l + 1]: lsum += nums[l] l += 1 - + # Strictly decreasing from right while r > 0 and nums[r - 1] > nums[r]: rsum += nums[r] r -= 1 - + # Single peak element if l == r: option1 = abs((lsum + nums[l]) - rsum) @@ -27,4 +27,3 @@ def splitArray(self, nums: List[int]) -> int: # Invalid mountain else: return -1 - diff --git a/solutions/3701/01.py b/solutions/3701/01.py index dbcf31c..145ac28 100644 --- a/solutions/3701/01.py +++ b/solutions/3701/01.py @@ -1,5 +1,6 @@ from typing import List + class Solution: def alternatingSum(self, nums: List[int]) -> int: result = 0 @@ -11,4 +12,3 @@ def alternatingSum(self, nums: List[int]) -> int: # Odd index: subtract result -= num return result - diff --git a/solutions/3707/01.py b/solutions/3707/01.py index 1a7ca05..d9512b2 100644 --- a/solutions/3707/01.py +++ b/solutions/3707/01.py @@ -1,7 +1,7 @@ class Solution: def scoreBalance(self, s: str) -> bool: n = len(s) - + # Try all possible split positions # Split at index i means: left = s[0..i], right = s[i+1..n-1] # Both must be non-empty, so i can range from 0 to n-2 @@ -9,16 +9,15 @@ def scoreBalance(self, s: str) -> bool: # Calculate score of left substring s[0..i] left_score = 0 for j in range(i + 1): - left_score += ord(s[j]) - ord('a') + 1 - + left_score += ord(s[j]) - ord("a") + 1 + # Calculate score of right substring s[i+1..n-1] right_score = 0 for j in range(i + 1, n): - right_score += ord(s[j]) - ord('a') + 1 - + right_score += ord(s[j]) - ord("a") + 1 + # Check if scores are equal if left_score == right_score: return True - - return False + return False diff --git a/solutions/3712/01.py b/solutions/3712/01.py index 711fd39..a76b591 100644 --- a/solutions/3712/01.py +++ b/solutions/3712/01.py @@ -1,18 +1,18 @@ from typing import List from collections import Counter + class Solution: def sumDivisibleByK(self, nums: List[int], k: int) -> int: # Count frequency of each element freq = Counter(nums) - + res = 0 - + # For each element, if its frequency is divisible by k, # add the element * frequency to the sum for num, count in freq.items(): if count % k == 0: res += num * count - - return res + return res diff --git a/solutions/3716/01.py b/solutions/3716/01.py new file mode 100644 index 0000000..3c7c0ec --- /dev/null +++ b/solutions/3716/01.py @@ -0,0 +1,51 @@ +# SQL solution wrapped in Python for frontend display +import pandas as pd + + +def find_churn_risk_customers(subscription_events: pd.DataFrame) -> pd.DataFrame: + """ + Find customers at risk of churning. + + A customer is at churn risk if they: + 1. Currently have an active subscription (last event is not cancel) + 2. Have performed at least one downgrade + 3. Current plan revenue < 50% of historical maximum + 4. Have been a subscriber for at least 60 days + """ + query = """ + WITH query_cte AS ( + SELECT + user_id, + event_date, + MAX(event_date) OVER(PARTITION BY user_id) max_event_date, + event_type, + plan_name current_plan, + monthly_amount, + MAX(monthly_amount) OVER(PARTITION BY user_id) max_historical_amount, + DATEDIFF(MAX(event_date) OVER(PARTITION BY user_id), MIN(event_date) OVER(PARTITION BY user_id)) days_as_subscriber + FROM subscription_events + ) + SELECT + user_id, + current_plan, + monthly_amount current_monthly_amount, + max_historical_amount, + days_as_subscriber + FROM query_cte q + WHERE event_date = max_event_date + AND event_type <> 'cancel' + AND EXISTS ( + SELECT 1 + FROM query_cte q1 + WHERE q.user_id = q1.user_id + AND q1.event_type = 'downgrade' + ) + AND days_as_subscriber > 59 + AND monthly_amount / CAST(max_historical_amount AS FLOAT) <= 0.5 + ORDER BY days_as_subscriber DESC, user_id + """ + # Note: This is a SQL solution. In actual LeetCode environment, + # this would be executed as raw SQL, not via pandas + return pd.read_sql( + query, con=None + ) # Placeholder - actual execution depends on LeetCode environment diff --git a/solutions/3716/01.sql b/solutions/3716/01.sql index 360c1c2..130da76 100644 --- a/solutions/3716/01.sql +++ b/solutions/3716/01.sql @@ -18,6 +18,7 @@ SELECT days_as_subscriber FROM query_cte q WHERE event_date = max_event_date + AND event_type <> 'cancel' AND EXISTS ( SELECT 1 FROM query_cte q1 @@ -26,6 +27,5 @@ WHERE event_date = max_event_date ) AND days_as_subscriber > 59 AND monthly_amount / CAST(max_historical_amount AS FLOAT) <= 0.5 - AND event_type <> 'cancel' ORDER BY days_as_subscriber DESC, user_id; diff --git a/solutions/3718/01.py b/solutions/3718/01.py index efa14ca..1b6a483 100644 --- a/solutions/3718/01.py +++ b/solutions/3718/01.py @@ -1,14 +1,14 @@ from typing import List + class Solution: def missingMultiple(self, nums: List[int], k: int) -> int: # Convert nums to a set for O(1) lookup nums_set = set(nums) - + # Iterate through positive multiples of k: k, 2k, 3k, ... multiple = k while True: if multiple not in nums_set: return multiple multiple += k - diff --git a/solutions/3722/01.py b/solutions/3722/01.py index e2ab632..3f856b6 100644 --- a/solutions/3722/01.py +++ b/solutions/3722/01.py @@ -2,7 +2,7 @@ class Solution: def lexSmallest(self, s: str) -> str: n = len(s) res = s - + # Try reversing first k characters for all k from 1 to n for k in range(1, n + 1): # Reverse first k characters @@ -10,13 +10,13 @@ def lexSmallest(self, s: str) -> str: candidate = reversed_prefix + s[k:] if candidate < res: res = candidate - + # Try reversing last k characters for all k from 1 to n for k in range(1, n + 1): # Reverse last k characters - reversed_suffix = s[n - k:][::-1] - candidate = s[:n - k] + reversed_suffix + reversed_suffix = s[n - k :][::-1] + candidate = s[: n - k] + reversed_suffix if candidate < res: res = candidate - + return res diff --git a/solutions/3726/01.py b/solutions/3726/01.py index 4c8e4dc..081d5e1 100644 --- a/solutions/3726/01.py +++ b/solutions/3726/01.py @@ -1,6 +1,6 @@ def removeZeros(n: int) -> int: - res = '' + res = "" for c in str(n): - if c != '0': + if c != "0": res += c return int(res) diff --git a/solutions/3727/01.py b/solutions/3727/01.py index d24a045..95593e1 100644 --- a/solutions/3727/01.py +++ b/solutions/3727/01.py @@ -1,21 +1,22 @@ from typing import List + class Solution: def maxAlternatingSum(self, nums: List[int]) -> int: # Since we can rearrange, we want to maximize the alternating sum # The pattern is: +a^2 - b^2 + c^2 - d^2 + ... # We need to assign numbers to positive (even index) and negative (odd index) positions # To maximize: put largest squares in positive positions, smallest squares in negative positions - + n = len(nums) squares = [x * x for x in nums] squares.sort(reverse=True) - + # Count how many positive and negative positions we have num_positive = (n + 1) // 2 # Even indices: 0, 2, 4, ... num_negative = n // 2 # Odd indices: 1, 3, 5, ... - + # Assign largest squares to positive positions, smallest to negative res = sum(squares[:num_positive]) - sum(squares[num_positive:]) - + return res diff --git a/solutions/373/01.py b/solutions/373/01.py index b39fce5..3930042 100644 --- a/solutions/373/01.py +++ b/solutions/373/01.py @@ -1,24 +1,26 @@ import heapq + class Solution: - def kSmallestPairs(self, nums1: List[int], nums2: List[int], k: int) -> List[List[int]]: + def kSmallestPairs( + self, nums1: List[int], nums2: List[int], k: int + ) -> List[List[int]]: if not nums1 or not nums2: return [] - + heap = [] res = [] - + # Initialize heap with pairs (nums1[0], nums2[j], 0, j) for j in range(min(k, len(nums2))): heapq.heappush(heap, (nums1[0] + nums2[j], 0, j)) - + while heap and len(res) < k: _, i, j = heapq.heappop(heap) res.append([nums1[i], nums2[j]]) - + # Add next pair from nums1 if available if i + 1 < len(nums1): heapq.heappush(heap, (nums1[i + 1] + nums2[j], i + 1, j)) - - return res + return res diff --git a/solutions/3731/01.py b/solutions/3731/01.py index cda0480..ce475b1 100644 --- a/solutions/3731/01.py +++ b/solutions/3731/01.py @@ -1,19 +1,19 @@ from typing import List + class Solution: def findMissingElements(self, nums: List[int]) -> List[int]: # Find the minimum and maximum values min_val = min(nums) max_val = max(nums) - + # Convert nums to a set for O(1) lookup nums_set = set(nums) - + # Find all missing elements in the range [min_val, max_val] missing = [] for num in range(min_val + 1, max_val): if num not in nums_set: missing.append(num) - - return missing + return missing diff --git a/solutions/3733/01.py b/solutions/3733/01.py index 354b6d2..5766131 100644 --- a/solutions/3733/01.py +++ b/solutions/3733/01.py @@ -36,4 +36,3 @@ def can_complete(T): left = mid + 1 return left - diff --git a/solutions/3736/01.py b/solutions/3736/01.py index 6ccec05..2403d1d 100644 --- a/solutions/3736/01.py +++ b/solutions/3736/01.py @@ -1,15 +1,15 @@ from typing import List + class Solution: def minMoves(self, nums: List[int]) -> int: # Find the maximum value in the array max_val = max(nums) - + # Calculate the total moves needed # For each element, we need to increase it by (max_val - element) to reach max_val total_moves = 0 for num in nums: total_moves += max_val - num - - return total_moves + return total_moves diff --git a/solutions/3737/01.py b/solutions/3737/01.py index 5412547..1871928 100644 --- a/solutions/3737/01.py +++ b/solutions/3737/01.py @@ -1,10 +1,11 @@ from typing import List + class Solution: def countMajoritySubarrays(self, nums: List[int], target: int) -> int: n = len(nums) res = 0 - + # Check all possible subarrays for i in range(n): count = 0 # Count of target in current subarray @@ -12,11 +13,10 @@ def countMajoritySubarrays(self, nums: List[int], target: int) -> int: # Add current element to subarray if nums[j] == target: count += 1 - + # Check if target is majority: 2 * count > length length = j - i + 1 if 2 * count > length: res += 1 - - return res + return res diff --git a/solutions/3738/01.py b/solutions/3738/01.py index f6109a6..3bcb073 100644 --- a/solutions/3738/01.py +++ b/solutions/3738/01.py @@ -1,9 +1,10 @@ from typing import List + class Solution: def longestSubarray(self, nums: List[int]) -> int: n = len(nums) - + # pref[i] = length of longest non-decreasing subarray ending at index i pref = [1] * n for i in range(1, n): @@ -11,7 +12,7 @@ def longestSubarray(self, nums: List[int]) -> int: pref[i] = pref[i - 1] + 1 else: pref[i] = 1 - + # suff[i] = length of longest non-decreasing subarray starting at index i suff = [1] * n for i in range(n - 2, -1, -1): @@ -19,10 +20,10 @@ def longestSubarray(self, nums: List[int]) -> int: suff[i] = suff[i + 1] + 1 else: suff[i] = 1 - + # Initial maximum: longest without replacement result = max(max(pref), max(suff)) - + # Try replacing each element for i in range(n): if i > 0 and i < n - 1: @@ -46,6 +47,5 @@ def longestSubarray(self, nums: List[int]) -> int: # Replace last element: can extend prefix ending at i-1 if i > 0: result = max(result, pref[i - 1] + 1) - - return result + return result diff --git a/solutions/3739/01.py b/solutions/3739/01.py index 8c093ef..24f8ec9 100644 --- a/solutions/3739/01.py +++ b/solutions/3739/01.py @@ -8,4 +8,3 @@ def minimumOperations(self, nums: List[int]) -> int: # Choose the minimum operations (always 1) res += 1 return res - diff --git a/solutions/374/01.py b/solutions/374/01.py index 489dffd..8ba2983 100644 --- a/solutions/374/01.py +++ b/solutions/374/01.py @@ -5,20 +5,20 @@ # otherwise return 0 # def guess(num: int) -> int: + class Solution: def guessNumber(self, n: int) -> int: left, right = 1, n - + while left <= right: mid = left + (right - left) // 2 result = guess(mid) - + if result == 0: return mid elif result == -1: right = mid - 1 else: left = mid + 1 - - return left + return left diff --git a/solutions/3740/01.py b/solutions/3740/01.py index 0a3085b..38eefbd 100644 --- a/solutions/3740/01.py +++ b/solutions/3740/01.py @@ -1,23 +1,24 @@ from typing import List from collections import defaultdict + class Solution: def minimumDistance(self, nums: List[int]) -> int: # Group indices by value indices_map = defaultdict(list) for i, num in enumerate(nums): indices_map[num].append(i) - - min_distance = float('inf') - + + min_distance = float("inf") + # For each value that appears at least 3 times for num, indices in indices_map.items(): if len(indices) < 3: continue - + # Sort indices (they should already be sorted, but just to be safe) indices.sort() - + # Check every three consecutive indices # For indices p < q < r, the distance is 2 * (r - p) # We want to minimize r - p, so we check consecutive triplets @@ -25,11 +26,10 @@ def minimumDistance(self, nums: List[int]) -> int: p = indices[i] q = indices[i + 1] r = indices[i + 2] - + # Distance formula: abs(p - q) + abs(q - r) + abs(r - p) # Since p < q < r, this simplifies to: (q - p) + (r - q) + (r - p) = 2 * (r - p) distance = 2 * (r - p) min_distance = min(min_distance, distance) - - return min_distance if min_distance != float('inf') else -1 + return min_distance if min_distance != float("inf") else -1 diff --git a/solutions/3741/01.py b/solutions/3741/01.py index 0a3085b..38eefbd 100644 --- a/solutions/3741/01.py +++ b/solutions/3741/01.py @@ -1,23 +1,24 @@ from typing import List from collections import defaultdict + class Solution: def minimumDistance(self, nums: List[int]) -> int: # Group indices by value indices_map = defaultdict(list) for i, num in enumerate(nums): indices_map[num].append(i) - - min_distance = float('inf') - + + min_distance = float("inf") + # For each value that appears at least 3 times for num, indices in indices_map.items(): if len(indices) < 3: continue - + # Sort indices (they should already be sorted, but just to be safe) indices.sort() - + # Check every three consecutive indices # For indices p < q < r, the distance is 2 * (r - p) # We want to minimize r - p, so we check consecutive triplets @@ -25,11 +26,10 @@ def minimumDistance(self, nums: List[int]) -> int: p = indices[i] q = indices[i + 1] r = indices[i + 2] - + # Distance formula: abs(p - q) + abs(q - r) + abs(r - p) # Since p < q < r, this simplifies to: (q - p) + (r - q) + (r - p) = 2 * (r - p) distance = 2 * (r - p) min_distance = min(min_distance, distance) - - return min_distance if min_distance != float('inf') else -1 + return min_distance if min_distance != float("inf") else -1 diff --git a/solutions/3742/01.py b/solutions/3742/01.py index 8a0dfbd..e68446b 100644 --- a/solutions/3742/01.py +++ b/solutions/3742/01.py @@ -1,56 +1,56 @@ from typing import List + class Solution: def maxPathScore(self, grid: List[List[int]], k: int) -> int: m, n = len(grid), len(grid[0]) - + # dp[i][j][c] = maximum score at cell (i,j) with total cost exactly c # Initialize with -1 to indicate unreachable states dp = [[[-1] * (k + 1) for _ in range(n)] for _ in range(m)] - + # Starting cell (0, 0) # Cost: 0 if grid[0][0] == 0, else 1 # Score: grid[0][0] start_cost = 0 if grid[0][0] == 0 else 1 start_score = grid[0][0] - + if start_cost <= k: dp[0][0][start_cost] = start_score - + # Fill the DP table for i in range(m): for j in range(n): # Skip if we're at the starting cell (already initialized) if i == 0 and j == 0: continue - + # Calculate cost and score for current cell cell_cost = 0 if grid[i][j] == 0 else 1 cell_score = grid[i][j] - + # Try coming from top (i-1, j) if i > 0: for prev_cost in range(k + 1): - if dp[i-1][j][prev_cost] != -1: + if dp[i - 1][j][prev_cost] != -1: new_cost = prev_cost + cell_cost if new_cost <= k: - new_score = dp[i-1][j][prev_cost] + cell_score + new_score = dp[i - 1][j][prev_cost] + cell_score dp[i][j][new_cost] = max(dp[i][j][new_cost], new_score) - + # Try coming from left (i, j-1) if j > 0: for prev_cost in range(k + 1): - if dp[i][j-1][prev_cost] != -1: + if dp[i][j - 1][prev_cost] != -1: new_cost = prev_cost + cell_cost if new_cost <= k: - new_score = dp[i][j-1][prev_cost] + cell_score + new_score = dp[i][j - 1][prev_cost] + cell_score dp[i][j][new_cost] = max(dp[i][j][new_cost], new_score) - + # Find maximum score at destination (m-1, n-1) for any cost <= k result = -1 for cost in range(k + 1): - if dp[m-1][n-1][cost] != -1: - result = max(result, dp[m-1][n-1][cost]) - - return result + if dp[m - 1][n - 1][cost] != -1: + result = max(result, dp[m - 1][n - 1][cost]) + return result diff --git a/solutions/3743/01.py b/solutions/3743/01.py index e9c0a74..2b2f686 100644 --- a/solutions/3743/01.py +++ b/solutions/3743/01.py @@ -5,13 +5,12 @@ def beautifulSubarrays(self, nums: List[int]) -> int: prefix_xor = 0 count = {0: 1} # Initialize with 0 XOR (empty prefix) res = 0 - + for num in nums: prefix_xor ^= num # If we've seen this prefix_xor before, the subarray between # those two positions has XOR 0 (beautiful) res += count.get(prefix_xor, 0) count[prefix_xor] = count.get(prefix_xor, 0) + 1 - - return res + return res diff --git a/solutions/3745/01.py b/solutions/3745/01.py index 419871c..273675d 100644 --- a/solutions/3745/01.py +++ b/solutions/3745/01.py @@ -1,11 +1,12 @@ from typing import List + class Solution: def maximizeExpressionOfThree(self, nums: List[int]) -> int: # Sort the array in descending order # This allows us to easily access the two largest and smallest values sorted_nums = sorted(nums, reverse=True) - + # To maximize a + b - c: # - a and b should be the two largest values (maximize addition) # - c should be the smallest value (minimize subtraction, i.e., subtract the smallest) @@ -14,4 +15,3 @@ def maximizeExpressionOfThree(self, nums: List[int]) -> int: # - sorted_nums[1] is the second largest # - sorted_nums[-1] is the smallest return sorted_nums[0] + sorted_nums[1] - sorted_nums[-1] - diff --git a/solutions/3747/01.py b/solutions/3747/01.py index 33488cd..dacae6b 100644 --- a/solutions/3747/01.py +++ b/solutions/3747/01.py @@ -2,22 +2,22 @@ class Solution: def countDistinct(self, n: int) -> int: s = str(n) length = len(s) - + pow9 = [1] * (length + 1) for i in range(1, length + 1): - pow9[i] = pow9[i-1] * 9 - + pow9[i] = pow9[i - 1] * 9 + res = 0 # Count zero-free numbers with fewer digits for d in range(1, length): res += pow9[d] - + # Count zero-free numbers with same length as n for i, ch in enumerate(s): digit = int(ch) if digit == 0: return res res += (digit - 1) * pow9[length - i - 1] - + # n itself is zero-free return res + 1 diff --git a/solutions/3748/01.py b/solutions/3748/01.py index cd44d5b..e2e19be 100644 --- a/solutions/3748/01.py +++ b/solutions/3748/01.py @@ -1,14 +1,14 @@ class Solution: def beautifulSubstrings(self, s: str, k: int) -> int: - vowels = {'a', 'e', 'i', 'o', 'u'} + vowels = {"a", "e", "i", "o", "u"} n = len(s) - + # Find all x such that x^2 % k == 0 valid_x = [] for x in range(1, n + 1): if (x * x) % k == 0: valid_x.append(x) - + # Build prefix sum for vowels and consonants # Use +1 for vowel, -1 for consonant prefix = [0] @@ -17,7 +17,7 @@ def beautifulSubstrings(self, s: str, k: int) -> int: prefix.append(prefix[-1] + 1) else: prefix.append(prefix[-1] - 1) - + res = 0 # For each valid x, count substrings with vowels == consonants == x for x in valid_x: @@ -29,9 +29,8 @@ def beautifulSubstrings(self, s: str, k: int) -> int: if i >= 2 * x: prev_prefix = prefix[i - 2 * x] count_map[prev_prefix] = count_map.get(prev_prefix, 0) + 1 - + # Count matches res += count_map.get(prefix[i], 0) - - return res + return res diff --git a/solutions/3751/01.py b/solutions/3751/01.py index d81594d..af6c88d 100644 --- a/solutions/3751/01.py +++ b/solutions/3751/01.py @@ -3,30 +3,30 @@ def totalWaviness(self, num1: int, num2: int) -> int: def get_waviness(num: int) -> int: # Convert number to string to access digits s = str(num) - + # Numbers with fewer than 3 digits have waviness 0 if len(s) < 3: return 0 - + waviness = 0 # Check each middle digit (not first or last) for i in range(1, len(s) - 1): digit = int(s[i]) left = int(s[i - 1]) right = int(s[i + 1]) - + # Check if it's a peak (strictly greater than both neighbors) if digit > left and digit > right: waviness += 1 # Check if it's a valley (strictly less than both neighbors) elif digit < left and digit < right: waviness += 1 - + return waviness - + # Sum waviness for all numbers in the range total = 0 for num in range(num1, num2 + 1): total += get_waviness(num) - + return total diff --git a/solutions/3752/01.py b/solutions/3752/01.py index 9564c8c..6423329 100644 --- a/solutions/3752/01.py +++ b/solutions/3752/01.py @@ -41,4 +41,3 @@ def lexSmallestNegatedPerm(self, n: int, target: int) -> list[int]: res.sort() return res - diff --git a/solutions/3753/01.py b/solutions/3753/01.py index 1e1242e..7a93dff 100644 --- a/solutions/3753/01.py +++ b/solutions/3753/01.py @@ -1,5 +1,6 @@ from functools import lru_cache + class Solution: def totalWaviness(self, num1: int, num2: int) -> int: w1 = self._total_waviness_upto(num1 - 1) @@ -42,7 +43,9 @@ def dfs(pos, p1, p2, tight, has_started): # If we have enough digits to form a triple, check peak/valley if has_started and next_started and p1 is not None and p2 is not None: if (p2 < p1 > d) or (p2 > p1 < d): - total_waviness += sub_count # this peak/valley applies to all completions + total_waviness += ( + sub_count # this peak/valley applies to all completions + ) return total_waviness, total_count diff --git a/solutions/3754/01.py b/solutions/3754/01.py index 425a2a7..75ddc50 100644 --- a/solutions/3754/01.py +++ b/solutions/3754/01.py @@ -17,4 +17,3 @@ def sumAndMultiply(self, n: int) -> int: res = x * digit_sum return res - diff --git a/solutions/3757/01.py b/solutions/3757/01.py index b1b5f12..0ebe742 100644 --- a/solutions/3757/01.py +++ b/solutions/3757/01.py @@ -1,26 +1,27 @@ from typing import List + class Solution: def countEffective(self, nums: List[int]) -> int: MOD = 10**9 + 7 n = len(nums) - + # Step 1: Calculate total OR - all "light bulbs" that are on full = 0 for v in nums: full |= v - + if full == 0: return 0 - + # Step 2: Find which bits are set in the total OR # These are the "light bulbs" we care about bits = [i for i in range(31) if (full >> i) & 1] B = len(bits) - + # Create a mapping from bit position to index in our compressed representation idx = {bits[i]: i for i in range(B)} - + # Step 3: Map each number to a bitmask showing which bits it contributes to # freq[mask] = count of numbers that contribute exactly the bits in mask freq = [0] * (1 << B) @@ -30,7 +31,7 @@ def countEffective(self, nums: List[int]) -> int: if (v >> b) & 1: m |= 1 << idx[b] freq[m] += 1 - + # Step 4: SOS DP - count how many numbers are submasks of each mask # dp[mask] = count of numbers that contribute only bits contained in mask dp = freq[:] @@ -38,19 +39,19 @@ def countEffective(self, nums: List[int]) -> int: for mask in range(1 << B): if mask & (1 << i): dp[mask] += dp[mask ^ (1 << i)] - + # Precompute powers of 2 pow2 = [1] * (n + 1) for i in range(1, n + 1): pow2[i] = (pow2[i - 1] * 2) % MOD - + # Step 5: Inclusion-Exclusion to count effective subsequences # A subsequence is effective if it removes all "guardians" of at least one bit # We count subsequences that keep bits in mask s (removing bits in comp) # and subtract/add based on how many bits are removed res = 0 full_mask = (1 << B) - 1 - + # Iterate over all non-empty subsets of bits to keep for s in range(1, 1 << B): # comp = bits we're removing (complement of s) @@ -59,12 +60,12 @@ def countEffective(self, nums: List[int]) -> int: # These are the numbers we can freely include/exclude count_zero = dp[comp] term = pow2[count_zero] - + # Inclusion-exclusion: sign depends on popcount(s) (bits kept) # This follows from the inclusion-exclusion formula structure if s.bit_count() & 1: res = (res + term) % MOD else: res = (res - term) % MOD - + return res % MOD diff --git a/solutions/3761/01.py b/solutions/3761/01.py index f2da208..3858b0c 100644 --- a/solutions/3761/01.py +++ b/solutions/3761/01.py @@ -3,19 +3,19 @@ def minMirrorPairDistance(self, nums: List[int]) -> int: def reverse_num(n): # Reverse digits, removing leading zeros return int(str(n)[::-1]) - + # Map: reversed value -> most recent index seen = {} - res = float('inf') - + res = float("inf") + for i, num in enumerate(nums): reversed_val = reverse_num(num) - + # Check if current number matches any reversed value we've seen if num in seen: res = min(res, i - seen[num]) - + # Store current index under the reversed value seen[reversed_val] = i - - return res if res != float('inf') else -1 + + return res if res != float("inf") else -1 diff --git a/solutions/3764/01.py b/solutions/3764/01.py index ba10621..8e529ec 100644 --- a/solutions/3764/01.py +++ b/solutions/3764/01.py @@ -7,56 +7,55 @@ WITH top_performers AS ( -- Step 1: Identify top-performing students -- Must have at least 5 courses with average rating >= 4 - SELECT + SELECT user_id - FROM + FROM course_completions - GROUP BY + GROUP BY user_id - HAVING - COUNT(*) >= 5 + HAVING + COUNT(*) >= 5 AND AVG(course_rating) >= 4 ), ordered_courses AS ( -- Step 2: Get courses for top performers in chronological order - SELECT + SELECT cc.user_id, cc.course_name, cc.completion_date, ROW_NUMBER() OVER ( - PARTITION BY cc.user_id + PARTITION BY cc.user_id ORDER BY cc.completion_date ) AS course_order - FROM + FROM course_completions cc - INNER JOIN + INNER JOIN top_performers tp ON cc.user_id = tp.user_id ), course_pairs AS ( -- Step 3: Create consecutive course pairs - SELECT + SELECT oc1.course_name AS first_course, oc2.course_name AS second_course - FROM + FROM ordered_courses oc1 - INNER JOIN - ordered_courses oc2 - ON oc1.user_id = oc2.user_id + INNER JOIN + ordered_courses oc2 + ON oc1.user_id = oc2.user_id AND oc2.course_order = oc1.course_order + 1 ) -- Step 4: Count pair frequencies and order results -SELECT +SELECT first_course, second_course, COUNT(*) AS transition_count -FROM +FROM course_pairs -GROUP BY - first_course, +GROUP BY + first_course, second_course -ORDER BY +ORDER BY transition_count DESC, first_course ASC, second_course ASC; """ - diff --git a/solutions/3765/01.py b/solutions/3765/01.py index f07a33f..bb35305 100644 --- a/solutions/3765/01.py +++ b/solutions/3765/01.py @@ -7,24 +7,24 @@ def is_prime(n): return True if n % 2 == 0: return False - for i in range(3, int(n ** 0.5) + 1, 2): + for i in range(3, int(n**0.5) + 1, 2): if n % i == 0: return False return True - + s = str(num) n = len(s) - + # Check all prefixes for i in range(1, n + 1): prefix = int(s[:i]) if not is_prime(prefix): return False - + # Check all suffixes for i in range(n): suffix = int(s[i:]) if not is_prime(suffix): return False - + return True diff --git a/solutions/3766/01.py b/solutions/3766/01.py index c9c53e3..3e6eba8 100644 --- a/solutions/3766/01.py +++ b/solutions/3766/01.py @@ -4,27 +4,28 @@ def minOperations(self, nums: List[int]) -> List[int]: def is_binary_palindrome(n): binary = bin(n)[2:] return binary == binary[::-1] - + # Generate all binary palindromes palindromes = [] for i in range(1, 5001): if is_binary_palindrome(i): palindromes.append(i) - + res = [] for num in nums: # Use binary search to find closest palindrome import bisect + idx = bisect.bisect_left(palindromes, num) - - min_ops = float('inf') + + min_ops = float("inf") # Check the palindrome at idx (if exists) if idx < len(palindromes): min_ops = min(min_ops, abs(num - palindromes[idx])) # Check the palindrome before idx (if exists) if idx > 0: min_ops = min(min_ops, abs(num - palindromes[idx - 1])) - + res.append(min_ops) - + return res diff --git a/solutions/3767/01.py b/solutions/3767/01.py index a712ce2..d125a15 100644 --- a/solutions/3767/01.py +++ b/solutions/3767/01.py @@ -1,23 +1,23 @@ class Solution: def maxPoints(self, technique1: List[int], technique2: List[int], k: int) -> int: n = len(technique1) - + # Start with all tasks using technique1 total = sum(technique1) - + # Calculate deltas: switching from technique1 to technique2 deltas = [technique2[i] - technique1[i] for i in range(n)] - + # Sort deltas in descending order deltas.sort(reverse=True) - + res = total - + # We need at least k tasks using technique1 # So we can switch at most (n - k) tasks to technique2 # Apply the largest positive deltas for i in range(n - k): total += deltas[i] res = max(res, total) - + return res diff --git a/solutions/3768/01.py b/solutions/3768/01.py index 4323216..de5b655 100644 --- a/solutions/3768/01.py +++ b/solutions/3768/01.py @@ -5,37 +5,37 @@ def minInversionCount(self, nums: List[int], k: int) -> int: comp_map = {val: idx + 1 for idx, val in enumerate(sorted_nums)} compressed = [comp_map[num] for num in nums] n = len(compressed) - + # Fenwick Tree (Binary Indexed Tree) for counting class FenwickTree: def __init__(self, size): self.n = size self.tree = [0] * (size + 1) - + def update(self, idx, delta): while idx <= self.n: self.tree[idx] += delta idx += idx & -idx - + def query(self, idx): res = 0 while idx > 0: res += self.tree[idx] idx -= idx & -idx return res - + # Initialize Fenwick Tree ft = FenwickTree(n) - + # Calculate inversion count for first window inv_count = 0 for i in range(k): # Count numbers greater than compressed[i] in current window inv_count += i - ft.query(compressed[i]) ft.update(compressed[i], 1) - + res = inv_count - + # Slide window for i in range(k, n): # Remove leftmost element @@ -44,14 +44,14 @@ def query(self, idx): removed = compressed[i - k] smaller = ft.query(removed - 1) inv_count -= smaller - + # Add new element new_val = compressed[i] # Count numbers greater than new element in current window greater = (k - 1) - ft.query(new_val) inv_count += greater ft.update(new_val, 1) - + res = min(res, inv_count) - + return res diff --git a/solutions/3769/01.py b/solutions/3769/01.py index a3a3a7c..809cb3b 100644 --- a/solutions/3769/01.py +++ b/solutions/3769/01.py @@ -5,8 +5,7 @@ def binary_reflection(n): binary = bin(n)[2:] # Remove '0b' prefix reversed_binary = binary[::-1] # Reverse the string return int(reversed_binary, 2) # Convert back to int - + # Sort by binary reflection, then by original value if reflection is same res = sorted(nums, key=lambda x: (binary_reflection(x), x)) return res - diff --git a/solutions/3770/01.py b/solutions/3770/01.py index 9a507a7..b754b91 100644 --- a/solutions/3770/01.py +++ b/solutions/3770/01.py @@ -3,18 +3,18 @@ def largestPrime(self, n: int) -> int: # Sieve of Eratosthenes is_prime = [True] * (n + 1) is_prime[0] = is_prime[1] = False - - for i in range(2, int(n ** 0.5) + 1): + + for i in range(2, int(n**0.5) + 1): if is_prime[i]: for j in range(i * i, n + 1, i): is_prime[j] = False - + # Get all primes primes = [i for i in range(2, n + 1) if is_prime[i]] - + if not primes: return 0 - + # Only check consecutive sums starting from 2 (first prime) res = 0 current_sum = 0 @@ -26,5 +26,5 @@ def largestPrime(self, n: int) -> int: # Check if sum is prime and <= n if current_sum <= n and is_prime[current_sum]: res = max(res, current_sum) - + return res diff --git a/solutions/3771/01.py b/solutions/3771/01.py index a8abd5a..5cf3f47 100644 --- a/solutions/3771/01.py +++ b/solutions/3771/01.py @@ -1,20 +1,21 @@ class Solution: def totalScore(self, hp: int, damage: List[int], requirement: List[int]) -> int: n = len(damage) - + # Prefix sums for damage prefix = [0] * (n + 1) for i in range(n): prefix[i + 1] = prefix[i] + damage[i] - + # For each room j, count how many starting positions i <= j # would result in earning a point at room j # Condition: hp - (prefix[j+1] - prefix[i]) >= requirement[j] # => hp - prefix[j+1] + prefix[i] >= requirement[j] # => prefix[i] >= requirement[j] - hp + prefix[j+1] - + res = 0 import bisect + for j in range(n): threshold = requirement[j] - hp + prefix[j + 1] # Use binary search to find first index where prefix[i] >= threshold @@ -22,5 +23,5 @@ def totalScore(self, hp: int, damage: List[int], requirement: List[int]) -> int: idx = bisect.bisect_left(prefix, threshold, hi=j + 1) # All indices from idx to j (inclusive) satisfy the condition res += max(0, j + 1 - idx) - + return res diff --git a/solutions/3774/01.py b/solutions/3774/01.py index 060f7b7..719590d 100644 --- a/solutions/3774/01.py +++ b/solutions/3774/01.py @@ -1,15 +1,13 @@ class Solution: def absDifference(self, nums: List[int], k: int) -> int: # Sort the array - sorted_nums = sorted(nums) - n = len(sorted_nums) - + nums.sort() + # Sum of k largest elements (last k elements) - sum_largest = sum(sorted_nums[n - k:]) - + sum_largest = sum(nums[-k:]) + # Sum of k smallest elements (first k elements) - sum_smallest = sum(sorted_nums[:k]) - + sum_smallest = sum(nums[:k]) + # Return absolute difference - res = abs(sum_largest - sum_smallest) - return res + return abs(sum_largest - sum_smallest) diff --git a/solutions/3775/01.py b/solutions/3775/01.py index 97c0dd2..a0f87ce 100644 --- a/solutions/3775/01.py +++ b/solutions/3775/01.py @@ -1,25 +1,24 @@ class Solution: def reverseWords(self, s: str) -> str: - def count_vowels(word): - vowels = {'a', 'e', 'i', 'o', 'u'} - return sum(1 for char in word if char in vowels) - words = s.split() + if not words: - return s - - # Count vowels in first word - first_vowel_count = count_vowels(words[0]) - + return "" + + # Count vowels in the first word + first_word_vowels = sum(1 for c in words[0] if c in "aeiou") + # Process remaining words res = [words[0]] - for i in range(1, len(words)): - word = words[i] - vowel_count = count_vowels(word) - if vowel_count == first_vowel_count: - # Reverse the word + + for word in words[1:]: + # Count vowels in current word + vowel_count = sum(1 for c in word if c in "aeiou") + + # If vowel count matches first word, reverse it + if vowel_count == first_word_vowels: res.append(word[::-1]) else: res.append(word) - - return ' '.join(res) + + return " ".join(res) diff --git a/solutions/3776/01.py b/solutions/3776/01.py index ccf2eaa..f2e98ed 100644 --- a/solutions/3776/01.py +++ b/solutions/3776/01.py @@ -1,46 +1,34 @@ class Solution: def minMoves(self, balance: List[int]) -> int: n = len(balance) - total = sum(balance) - - # If total is negative, impossible - if total < 0: - return -1 - + # Find the index with negative balance - neg_idx = None - for i in range(n): - if balance[i] < 0: - neg_idx = i + j = -1 + for i, b in enumerate(balance): + if b < 0: + j = i break - - # If no negative balance, already balanced - if neg_idx is None: + + # If all balances are non-negative, return 0 + if j < 0: return 0 - - # We need to transfer balance to neg_idx - # Greedily use nearest positive balances + + # If total sum is negative, impossible + if sum(balance) < 0: + return -1 + + # Work with a copy to avoid modifying input + A = balance[:] res = 0 - neg_amount = abs(balance[neg_idx]) - - # Create list of (distance, index, amount) for positive balances - positives = [] - for i in range(n): - if balance[i] > 0: - # Calculate distance (circular) - dist = min(abs(i - neg_idx), n - abs(i - neg_idx)) - positives.append((dist, i, balance[i])) - - # Sort by distance - positives.sort() - - # Greedily transfer from nearest positives - remaining = neg_amount - for dist, idx, amount in positives: - if remaining <= 0: - break - transfer = min(remaining, amount) - res += transfer * dist - remaining -= transfer - + d = 0 + + # Expand outward from negative index + while A[j] < 0: + d += 1 + # Get storage from neighbors at distance d + storage = A[(j + d) % n] + A[(j - d) % n] + transfer = min(-A[j], storage) + res += transfer * d + A[j] += storage + return res diff --git a/solutions/3777/01.py b/solutions/3777/01.py index 382a9d6..4b71bcd 100644 --- a/solutions/3777/01.py +++ b/solutions/3777/01.py @@ -1,12 +1,12 @@ class FenwickTree: def __init__(self, size): self.tree = [0] * (size + 1) - + def add(self, i, delta): while i < len(self.tree): self.tree[i] += delta i += i & (-i) - + def query(self, i): s = 0 while i > 0: @@ -14,26 +14,27 @@ def query(self, i): i -= i & (-i) return s + class Solution: def minDeletions(self, s: str, queries: List[List[int]]) -> List[int]: n = len(s) # Convert string to 0-1 array (A=0, B=1) - A = [ord(c) - ord('A') for c in s] - + A = [ord(c) - ord("A") for c in s] + # Initialize Fenwick Tree bit = FenwickTree(n) # Mark violations (adjacent identical characters) for i in range(n - 1): if A[i] == A[i + 1]: bit.add(i + 1, 1) - + res = [] for q in queries: if q[0] == 1: # Flip operation i = q[1] A[i] ^= 1 # Flip the bit - + # Update violations at position i and i+1 if i > 0: # Check violation with left neighbor @@ -45,5 +46,5 @@ def minDeletions(self, s: str, queries: List[List[int]]) -> List[int]: # Query operation: count violations in range [l, r] # Number of violations = minimum deletions needed res.append(bit.query(q[2]) - bit.query(q[1])) - + return res diff --git a/solutions/3779/01.py b/solutions/3779/01.py new file mode 100644 index 0000000..bee387a --- /dev/null +++ b/solutions/3779/01.py @@ -0,0 +1,13 @@ +class Solution: + def minOperations(self, nums: List[int]) -> int: + # Process from right to left using a copy + nums = nums[:] # Work with a copy to avoid modifying input + seen = {nums.pop()} + + while nums: + if nums[-1] in seen: + # Calculate operations needed: (remaining + 2) // 3 + return (len(nums) + 2) // 3 + seen.add(nums.pop()) + + return 0 diff --git a/solutions/378/01.py b/solutions/378/01.py index 7839e0a..15562b7 100644 --- a/solutions/378/01.py +++ b/solutions/378/01.py @@ -1,21 +1,20 @@ class Solution: def kthSmallest(self, matrix: List[List[int]], k: int) -> int: import heapq - + n = len(matrix) # Min heap: (value, row, col) heap = [] - + # Add first element of each row to heap for i in range(n): heapq.heappush(heap, (matrix[i][0], i, 0)) - + # Pop k-1 times to get kth smallest for _ in range(k - 1): val, row, col = heapq.heappop(heap) if col + 1 < n: heapq.heappush(heap, (matrix[row][col + 1], row, col + 1)) - + # The kth smallest is at the top return heap[0][0] - diff --git a/solutions/3780/01.py b/solutions/3780/01.py new file mode 100644 index 0000000..26c8fc2 --- /dev/null +++ b/solutions/3780/01.py @@ -0,0 +1,30 @@ +class Solution: + def maximumSum(self, nums: List[int]) -> int: + # Group numbers by remainder when divided by 3 + rem = [[], [], []] + for num in nums: + rem[num % 3].append(num) + + # Sort each group in descending order + for i in range(3): + rem[i].sort(reverse=True) + + res = 0 + + # Case 1: Three numbers with remainder 0 + if len(rem[0]) >= 3: + res = max(res, sum(rem[0][:3])) + + # Case 2: One from each remainder (0, 1, 2) + if rem[0] and rem[1] and rem[2]: + res = max(res, rem[0][0] + rem[1][0] + rem[2][0]) + + # Case 3: Three numbers with remainder 1 + if len(rem[1]) >= 3: + res = max(res, sum(rem[1][:3])) + + # Case 4: Three numbers with remainder 2 + if len(rem[2]) >= 3: + res = max(res, sum(rem[2][:3])) + + return res diff --git a/solutions/3781/01.py b/solutions/3781/01.py new file mode 100644 index 0000000..b8f7ef5 --- /dev/null +++ b/solutions/3781/01.py @@ -0,0 +1,19 @@ +class Solution: + def maximumScore(self, nums: List[int], s: str) -> int: + import heapq + + # Use max heap (negate values for Python's min heap) + heap = [] + res = 0 + + for i in range(len(nums)): + # Add current number to heap (negate for max heap) + heapq.heappush(heap, -nums[i]) + + # If s[i] == '1', we must select a number + if s[i] == "1": + # Get the maximum value from heap + max_val = -heapq.heappop(heap) + res += max_val + + return res diff --git a/solutions/3783/01.py b/solutions/3783/01.py new file mode 100644 index 0000000..6164701 --- /dev/null +++ b/solutions/3783/01.py @@ -0,0 +1,7 @@ +class Solution: + def mirrorDistance(self, n: int) -> int: + # Reverse the digits of n + reversed_n = int(str(n)[::-1]) + + # Return absolute difference + return abs(n - reversed_n) diff --git a/solutions/3784/01.py b/solutions/3784/01.py new file mode 100644 index 0000000..f80165d --- /dev/null +++ b/solutions/3784/01.py @@ -0,0 +1,15 @@ +class Solution: + def minCost(self, s: str, cost: List[int]) -> int: + from collections import defaultdict + + # Sum up costs for each character + char_to_cost = defaultdict(int) + for ch, co in zip(s, cost): + char_to_cost[ch] += co + + # Find the character with maximum total cost + max_cost = max(char_to_cost.values()) + + # Keep the character with max cost, delete all others + # Answer is total cost minus the max cost + return sum(cost) - max_cost diff --git a/solutions/380/01.py b/solutions/380/01.py index 5f52879..c41d1c1 100644 --- a/solutions/380/01.py +++ b/solutions/380/01.py @@ -1,5 +1,6 @@ import random + class RandomizedSet: def __init__(self): @@ -9,7 +10,7 @@ def __init__(self): def insert(self, val: int) -> bool: if val in self.val_to_index: return False - + self.val_to_index[val] = len(self.nums) self.nums.append(val) return True @@ -17,20 +18,19 @@ def insert(self, val: int) -> bool: def remove(self, val: int) -> bool: if val not in self.val_to_index: return False - + # Move last element to the position of element to remove index = self.val_to_index[val] last_val = self.nums[-1] - + self.nums[index] = last_val self.val_to_index[last_val] = index - + # Remove the last element self.nums.pop() del self.val_to_index[val] - + return True def getRandom(self) -> int: return random.choice(self.nums) - diff --git a/solutions/383/01.py b/solutions/383/01.py index d1f30e6..eccbbeb 100644 --- a/solutions/383/01.py +++ b/solutions/383/01.py @@ -4,12 +4,11 @@ def canConstruct(self, ransomNote: str, magazine: str) -> bool: char_count = {} for char in magazine: char_count[char] = char_count.get(char, 0) + 1 - + # Check if we can construct ransomNote for char in ransomNote: if char not in char_count or char_count[char] == 0: return False char_count[char] -= 1 - - return True + return True diff --git a/solutions/39/01.py b/solutions/39/01.py index e96f07a..4f2c7f9 100644 --- a/solutions/39/01.py +++ b/solutions/39/01.py @@ -1,22 +1,22 @@ from typing import List + class Solution: def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: res = [] - + def backtrack(remaining, combination, start): if remaining == 0: res.append(combination[:]) return - + if remaining < 0: return - + for i in range(start, len(candidates)): combination.append(candidates[i]) backtrack(remaining - candidates[i], combination, i) combination.pop() - + backtrack(target, [], 0) return res - diff --git a/solutions/392/01.py b/solutions/392/01.py index 6fe4255..d7919b7 100644 --- a/solutions/392/01.py +++ b/solutions/392/01.py @@ -2,12 +2,12 @@ class Solution: def isSubsequence(self, s: str, t: str) -> bool: i = 0 # pointer for s j = 0 # pointer for t - + # Traverse both strings while i < len(s) and j < len(t): if s[i] == t[j]: i += 1 # move pointer in s j += 1 # always move pointer in t - + # If we've matched all characters in s, it's a subsequence return i == len(s) diff --git a/solutions/394/01.py b/solutions/394/01.py index 62aa81d..0676f8b 100644 --- a/solutions/394/01.py +++ b/solutions/394/01.py @@ -3,23 +3,22 @@ def decodeString(self, s: str) -> str: stack = [] current_string = "" current_num = 0 - + for char in s: if char.isdigit(): # Build the number current_num = current_num * 10 + int(char) - elif char == '[': + elif char == "[": # Push current state to stack stack.append((current_string, current_num)) current_string = "" current_num = 0 - elif char == ']': + elif char == "]": # Pop and decode prev_string, num = stack.pop() current_string = prev_string + current_string * num else: # Regular character current_string += char - - return current_string + return current_string diff --git a/solutions/399/01.py b/solutions/399/01.py index 0c61daf..84c7fcf 100644 --- a/solutions/399/01.py +++ b/solutions/399/01.py @@ -1,40 +1,42 @@ from collections import defaultdict, deque + class Solution: - def calcEquation(self, equations: List[List[str]], values: List[float], queries: List[List[str]]) -> List[float]: + def calcEquation( + self, equations: List[List[str]], values: List[float], queries: List[List[str]] + ) -> List[float]: # Build graph: graph[a][b] = value means a / b = value graph = defaultdict(dict) - + for (a, b), value in zip(equations, values): graph[a][b] = value graph[b][a] = 1.0 / value - + def bfs(start, end): if start not in graph or end not in graph: return -1.0 - + if start == end: return 1.0 - + queue = deque([(start, 1.0)]) visited = {start} - + while queue: node, value = queue.popleft() - + if node == end: return value - + for neighbor, weight in graph[node].items(): if neighbor not in visited: visited.add(neighbor) queue.append((neighbor, value * weight)) - + return -1.0 - + res = [] for a, b in queries: res.append(bfs(a, b)) - - return res + return res diff --git a/solutions/4/01.py b/solutions/4/01.py index ee7927e..504e9e8 100644 --- a/solutions/4/01.py +++ b/solutions/4/01.py @@ -1,11 +1,12 @@ from typing import List + class Solution: def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float: # Merge the two arrays merged = [] i, j = 0, 0 - + while i < len(nums1) and j < len(nums2): if nums1[i] <= nums2[j]: merged.append(nums1[i]) @@ -13,15 +14,14 @@ def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float: else: merged.append(nums2[j]) j += 1 - + # Add remaining elements merged.extend(nums1[i:]) merged.extend(nums2[j:]) - + # Find median n = len(merged) if n % 2 == 0: return (merged[n // 2 - 1] + merged[n // 2]) / 2 else: return merged[n // 2] - diff --git a/solutions/409/01.py b/solutions/409/01.py index 91b634d..6cc38e1 100644 --- a/solutions/409/01.py +++ b/solutions/409/01.py @@ -1,14 +1,14 @@ class Solution: def longestPalindrome(self, s: str) -> int: char_count = {} - + # Count frequency of each character for char in s: char_count[char] = char_count.get(char, 0) + 1 - + length = 0 has_odd = False - + # For each character count for count in char_count.values(): # Add even pairs @@ -16,10 +16,9 @@ def longestPalindrome(self, s: str) -> int: # Check if there's an odd count (for center character) if count % 2 == 1: has_odd = True - + # Add 1 for center character if we have any odd counts if has_odd: length += 1 - - return length + return length diff --git a/solutions/412/01.py b/solutions/412/01.py index eb13654..3a9d0aa 100644 --- a/solutions/412/01.py +++ b/solutions/412/01.py @@ -11,4 +11,3 @@ def fizzBuzz(self, n: int) -> List[str]: else: res.append(str(i)) return res - diff --git a/solutions/42/01.py b/solutions/42/01.py index 49e32e9..ec4589e 100644 --- a/solutions/42/01.py +++ b/solutions/42/01.py @@ -1,35 +1,35 @@ def trap(height): """ Calculate the amount of water that can be trapped between walls. - + Args: height: List[int] - Array representing wall heights - + Returns: int - Total amount of water trapped """ # Handle edge cases if not height or len(height) < 3: return 0 - + n = len(height) - + # Step 1: Precompute left maximums # left_max[i] = highest wall to the left of position i (including i) left_max = [0] * n left_max[0] = height[0] - + for i in range(1, n): - left_max[i] = max(left_max[i-1], height[i]) - + left_max[i] = max(left_max[i - 1], height[i]) + # Step 2: Precompute right maximums # right_max[i] = highest wall to the right of position i (including i) right_max = [0] * n - right_max[n-1] = height[n-1] - - for i in range(n-2, -1, -1): - right_max[i] = max(right_max[i+1], height[i]) - + right_max[n - 1] = height[n - 1] + + for i in range(n - 2, -1, -1): + right_max[i] = max(right_max[i + 1], height[i]) + # Step 3: Calculate trapped water at each position res = 0 for i in range(n): @@ -38,5 +38,5 @@ def trap(height): water = min(left_max[i], right_max[i]) - height[i] if water > 0: res += water - - return res \ No newline at end of file + + return res diff --git a/solutions/427/01.py b/solutions/427/01.py index 7d3dfb0..38a2eba 100644 --- a/solutions/427/01.py +++ b/solutions/427/01.py @@ -10,13 +10,14 @@ def __init__(self, val, isLeaf, topLeft, topRight, bottomLeft, bottomRight): self.bottomRight = bottomRight """ + class Solution: - def construct(self, grid: List[List[int]]) -> 'Node': + def construct(self, grid: List[List[int]]) -> "Node": def build(r1, c1, r2, c2): # Check if all values in the grid are the same all_same = True first_val = grid[r1][c1] - + for i in range(r1, r2 + 1): for j in range(c1, c2 + 1): if grid[i][j] != first_val: @@ -24,22 +25,21 @@ def build(r1, c1, r2, c2): break if not all_same: break - + if all_same: return Node(first_val == 1, True, None, None, None, None) - + # Divide into four quadrants mid_r = (r1 + r2) // 2 mid_c = (c1 + c2) // 2 - + top_left = build(r1, c1, mid_r, mid_c) top_right = build(r1, mid_c + 1, mid_r, c2) bottom_left = build(mid_r + 1, c1, r2, mid_c) bottom_right = build(mid_r + 1, mid_c + 1, r2, c2) - + return Node(False, False, top_left, top_right, bottom_left, bottom_right) - + n = len(grid) res = build(0, 0, n - 1, n - 1) return res - diff --git a/solutions/433/01.py b/solutions/433/01.py index 1d00072..60406ff 100644 --- a/solutions/433/01.py +++ b/solutions/433/01.py @@ -1,31 +1,31 @@ from collections import deque + class Solution: def minMutation(self, startGene: str, endGene: str, bank: List[str]) -> int: if startGene == endGene: return 0 - + bank_set = set(bank) if endGene not in bank_set: return -1 - + queue = deque([(startGene, 0)]) visited = {startGene} - + while queue: gene, mutations = queue.popleft() - + if gene == endGene: return mutations - + # Try all possible mutations for i in range(len(gene)): - for char in ['A', 'C', 'G', 'T']: + for char in ["A", "C", "G", "T"]: if gene[i] != char: - new_gene = gene[:i] + char + gene[i+1:] + new_gene = gene[:i] + char + gene[i + 1 :] if new_gene in bank_set and new_gene not in visited: visited.add(new_gene) queue.append((new_gene, mutations + 1)) - - return -1 + return -1 diff --git a/solutions/435/01.py b/solutions/435/01.py index f5d91d6..561b1b0 100644 --- a/solutions/435/01.py +++ b/solutions/435/01.py @@ -1,16 +1,17 @@ from typing import List + class Solution: def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int: # Sort intervals by end time intervals.sort(key=lambda x: x[1]) - + # Count of intervals to remove res = 0 - + # Track the end time of the last kept interval - last_end = float('-inf') - + last_end = float("-inf") + # Iterate through sorted intervals for start, end in intervals: # If current interval doesn't overlap with last kept interval @@ -20,7 +21,5 @@ def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int: else: # Overlap detected, remove current interval res += 1 - - return res - + return res diff --git a/solutions/437/01.py b/solutions/437/01.py index c28088f..1943105 100644 --- a/solutions/437/01.py +++ b/solutions/437/01.py @@ -8,24 +8,23 @@ class Solution: def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int: res = 0 prefix_sums = {} - + def dfs(node, current_sum): nonlocal res, prefix_sums if not node: return - + current_sum += node.val if current_sum == targetSum: res += 1 - + res += prefix_sums.get(current_sum - targetSum, 0) prefix_sums[current_sum] = prefix_sums.get(current_sum, 0) + 1 - + dfs(node.left, current_sum) dfs(node.right, current_sum) - + prefix_sums[current_sum] -= 1 - + dfs(root, 0) return res - diff --git a/solutions/438/01.py b/solutions/438/01.py index 59ca285..2c9ee82 100644 --- a/solutions/438/01.py +++ b/solutions/438/01.py @@ -2,31 +2,30 @@ class Solution: def findAnagrams(self, s: str, p: str) -> List[int]: if len(p) > len(s): return [] - + # Count characters in p p_count = {} for char in p: p_count[char] = p_count.get(char, 0) + 1 - + # Sliding window window_count = {} res = [] left = 0 - + for right in range(len(s)): # Add right character window_count[s[right]] = window_count.get(s[right], 0) + 1 - + # If window size equals p length, check if it's an anagram if right - left + 1 == len(p): if window_count == p_count: res.append(left) - + # Remove left character window_count[s[left]] -= 1 if window_count[s[left]] == 0: del window_count[s[left]] left += 1 - - return res + return res diff --git a/solutions/443/01.py b/solutions/443/01.py index 1135072..4daacde 100644 --- a/solutions/443/01.py +++ b/solutions/443/01.py @@ -14,4 +14,4 @@ def compress(chars): for c in str(count): chars[write] = c write += 1 - return write \ No newline at end of file + return write diff --git a/solutions/448/01.py b/solutions/448/01.py index ab63f38..576855f 100644 --- a/solutions/448/01.py +++ b/solutions/448/01.py @@ -5,11 +5,11 @@ def findDisappearedNumbers(self, nums: List[int]) -> List[int]: idx = abs(num) - 1 if nums[idx] > 0: nums[idx] = -nums[idx] - + # Collect indices where value is still positive (these numbers are missing) res = [] for i in range(len(nums)): if nums[i] > 0: res.append(i + 1) - - return res \ No newline at end of file + + return res diff --git a/solutions/45/01.py b/solutions/45/01.py index 1ba01f4..5e8cf09 100644 --- a/solutions/45/01.py +++ b/solutions/45/01.py @@ -1,28 +1,28 @@ from typing import List + class Solution: def jump(self, nums: List[int]) -> int: n = len(nums) if n == 1: return 0 - + # Greedy approach: track farthest reachable position jumps = 0 current_end = 0 farthest = 0 - + for i in range(n - 1): # Update farthest reachable position farthest = max(farthest, i + nums[i]) - + # If we've reached the end of current jump range if i == current_end: jumps += 1 current_end = farthest - + # If we can reach the end, we're done if current_end >= n - 1: break - - return jumps + return jumps diff --git a/solutions/450/01.py b/solutions/450/01.py index 12455e3..c099090 100644 --- a/solutions/450/01.py +++ b/solutions/450/01.py @@ -5,11 +5,12 @@ # self.left = left # self.right = right + class Solution: def deleteNode(self, root, key: int): if not root: return None - + if key < root.val: root.left = self.deleteNode(root.left, key) elif key > root.val: @@ -28,11 +29,10 @@ def deleteNode(self, root, key: int): root.val = min_node.val # Delete the min node from right subtree root.right = self.deleteNode(root.right, min_node.val) - + return root - + def findMin(self, node): while node.left: node = node.left return node - diff --git a/solutions/452/01.py b/solutions/452/01.py index 05444c5..a99133c 100644 --- a/solutions/452/01.py +++ b/solutions/452/01.py @@ -1,16 +1,17 @@ from typing import List + class Solution: def findMinArrowShots(self, points: List[List[int]]) -> int: # Sort balloons by end coordinate points.sort(key=lambda x: x[1]) - + # Count of arrows needed res = 0 - + # Track the position of the last arrow - last_arrow = float('-inf') - + last_arrow = float("-inf") + # Iterate through sorted balloons for start, end in points: # If current balloon is not burst by last arrow @@ -18,7 +19,5 @@ def findMinArrowShots(self, points: List[List[int]]) -> int: # Need a new arrow at the end of this balloon res += 1 last_arrow = end - - return res - + return res diff --git a/solutions/46/01.py b/solutions/46/01.py index 88476ab..ea3471d 100644 --- a/solutions/46/01.py +++ b/solutions/46/01.py @@ -1,22 +1,22 @@ from typing import List + class Solution: def permute(self, nums: List[int]) -> List[List[int]]: res = [] - + def backtrack(current_permutation, remaining): if not remaining: res.append(current_permutation[:]) return - + for i in range(len(remaining)): # Choose current_permutation.append(remaining[i]) # Explore - backtrack(current_permutation, remaining[:i] + remaining[i+1:]) + backtrack(current_permutation, remaining[:i] + remaining[i + 1 :]) # Unchoose current_permutation.pop() - + backtrack([], nums) return res - diff --git a/solutions/460/01.py b/solutions/460/01.py index ddcfe0a..ac799ec 100644 --- a/solutions/460/01.py +++ b/solutions/460/01.py @@ -1,5 +1,6 @@ from collections import defaultdict, OrderedDict + class LFUCache: def __init__(self, capacity: int): @@ -12,39 +13,38 @@ def __init__(self, capacity: int): def get(self, key: int) -> int: if key not in self.key_to_val: return -1 - + # Update frequency freq = self.key_to_freq[key] self.freq_to_keys[freq].pop(key) - + if not self.freq_to_keys[freq] and freq == self.min_freq: self.min_freq += 1 - + self.key_to_freq[key] = freq + 1 self.freq_to_keys[freq + 1][key] = None - + return self.key_to_val[key] def put(self, key: int, value: int) -> None: if self.capacity == 0: return - + if key in self.key_to_val: # Update existing key self.key_to_val[key] = value self.get(key) # Update frequency return - + # Remove LFU key if at capacity if len(self.key_to_val) >= self.capacity: # Remove least recently used key with min_freq lfu_key, _ = self.freq_to_keys[self.min_freq].popitem(last=False) del self.key_to_val[lfu_key] del self.key_to_freq[lfu_key] - + # Add new key self.key_to_val[key] = value self.key_to_freq[key] = 1 self.freq_to_keys[1][key] = None self.min_freq = 1 - diff --git a/solutions/494/01.py b/solutions/494/01.py index 408f884..52c555b 100644 --- a/solutions/494/01.py +++ b/solutions/494/01.py @@ -1,26 +1,26 @@ from typing import List + class Solution: def findTargetSumWays(self, nums: List[int], target: int) -> int: # Use memoization to avoid recalculating memo = {} - + def dfs(index, current_sum): # Base case: if we've processed all numbers if index == len(nums): return 1 if current_sum == target else 0 - + # Check memoization if (index, current_sum) in memo: return memo[(index, current_sum)] - + # Try both adding and subtracting current number add = dfs(index + 1, current_sum + nums[index]) subtract = dfs(index + 1, current_sum - nums[index]) - + # Store result in memo memo[(index, current_sum)] = add + subtract return memo[(index, current_sum)] - - return dfs(0, 0) + return dfs(0, 0) diff --git a/solutions/5/01.py b/solutions/5/01.py index 1f6d9cc..0d73603 100644 --- a/solutions/5/01.py +++ b/solutions/5/01.py @@ -2,10 +2,10 @@ class Solution: def longestPalindrome(self, s: str) -> str: if not s: return "" - + start = 0 max_len = 1 - + def expand_around_center(left, right): nonlocal start, max_len while left >= 0 and right < len(s) and s[left] == s[right]: @@ -16,12 +16,11 @@ def expand_around_center(left, right): if length > max_len: max_len = length start = left + 1 - + for i in range(len(s)): # Check for odd-length palindromes expand_around_center(i, i) # Check for even-length palindromes expand_around_center(i, i + 1) - - return s[start:start + max_len] + return s[start : start + max_len] diff --git a/solutions/50/01.py b/solutions/50/01.py index efa3818..ec996f5 100644 --- a/solutions/50/01.py +++ b/solutions/50/01.py @@ -4,17 +4,16 @@ def myPow(self, x: float, n: int) -> float: if n < 0: x = 1 / x n = -n - + # Base case if n == 0: return 1.0 - + # Recursive approach: x^n = (x^(n/2))^2 if n is even # x^n = x * (x^(n/2))^2 if n is odd res = self.myPow(x, n // 2) - + if n % 2 == 0: return res * res else: return x * res * res - diff --git a/solutions/502/01.py b/solutions/502/01.py index 43f2ba5..094e8d7 100644 --- a/solutions/502/01.py +++ b/solutions/502/01.py @@ -1,26 +1,28 @@ import heapq + class Solution: - def findMaximizedCapital(self, k: int, w: int, profits: List[int], capital: List[int]) -> int: + def findMaximizedCapital( + self, k: int, w: int, profits: List[int], capital: List[int] + ) -> int: # Combine profits and capital, sort by capital projects = list(zip(capital, profits)) projects.sort() - + max_heap = [] i = 0 res = w - + for _ in range(k): # Add all projects we can afford to the heap while i < len(projects) and projects[i][0] <= res: heapq.heappush(max_heap, -projects[i][1]) # Negative for max heap i += 1 - + if not max_heap: break - + # Take the project with maximum profit res += -heapq.heappop(max_heap) - - return res + return res diff --git a/solutions/509/01.py b/solutions/509/01.py index 71d4bfe..8ad10df 100644 --- a/solutions/509/01.py +++ b/solutions/509/01.py @@ -2,15 +2,14 @@ class Solution: def fib(self, n: int) -> int: if n <= 1: return n - + # Use iterative approach to avoid stack overflow prev2 = 0 prev1 = 1 - + for i in range(2, n + 1): current = prev1 + prev2 prev2 = prev1 prev1 = current - - return prev1 + return prev1 diff --git a/solutions/52/01.py b/solutions/52/01.py index e6e2f84..ac8ff67 100644 --- a/solutions/52/01.py +++ b/solutions/52/01.py @@ -4,35 +4,34 @@ def totalNQueens(self, n: int) -> int: cols = set() diag1 = set() # row - col (constant for same diagonal) diag2 = set() # row + col (constant for same anti-diagonal) - + res = 0 - + def backtrack(row): nonlocal res # Base case: all rows have been placed if row == n: res += 1 return - + # Try placing a queen in each column of the current row for col in range(n): # Check if this position is under attack if col in cols or (row - col) in diag1 or (row + col) in diag2: continue - + # Place the queen cols.add(col) diag1.add(row - col) diag2.add(row + col) - + # Recurse to next row backtrack(row + 1) - + # Backtrack: remove the queen cols.remove(col) diag1.remove(row - col) diag2.remove(row + col) - + backtrack(0) return res - diff --git a/solutions/53/01.py b/solutions/53/01.py index fa3542e..67f4bab 100644 --- a/solutions/53/01.py +++ b/solutions/53/01.py @@ -1,10 +1,11 @@ from typing import List + class Solution: def maxSubArray(self, nums: List[int]) -> int: max_sum = nums[0] current_sum = 0 - + for num in nums: # If current sum becomes negative, reset it if current_sum < 0: @@ -13,6 +14,5 @@ def maxSubArray(self, nums: List[int]) -> int: current_sum += num # Update maximum sum max_sum = max(max_sum, current_sum) - - return max_sum + return max_sum diff --git a/solutions/530/01.py b/solutions/530/01.py index 304f43d..425a5a1 100644 --- a/solutions/530/01.py +++ b/solutions/530/01.py @@ -10,12 +10,11 @@ def inorder(node): if not node: return [] return inorder(node.left) + [node.val] + inorder(node.right) - + values = inorder(root) - res = float('inf') - + res = float("inf") + for i in range(len(values) - 1): res = min(res, values[i + 1] - values[i]) - - return res + return res diff --git a/solutions/543/01.py b/solutions/543/01.py index 8681559..6219927 100644 --- a/solutions/543/01.py +++ b/solutions/543/01.py @@ -7,21 +7,20 @@ class Solution: def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int: res = 0 - + def dfs(node): nonlocal res if not node: return 0 - + left_depth = dfs(node.left) right_depth = dfs(node.right) - + # Diameter passing through this node res = max(res, left_depth + right_depth) - + # Return depth of this subtree return 1 + max(left_depth, right_depth) - + dfs(root) return res - diff --git a/solutions/547/01.py b/solutions/547/01.py index b96a573..cc01a89 100644 --- a/solutions/547/01.py +++ b/solutions/547/01.py @@ -1,27 +1,27 @@ from typing import List + class Solution: def findCircleNum(self, isConnected: List[List[int]]) -> int: n = len(isConnected) visited = [False] * n res = 0 - + def dfs(city): # Mark current city as visited visited[city] = True - + # Check all other cities for neighbor in range(n): # If connected and not visited, visit it if isConnected[city][neighbor] == 1 and not visited[neighbor]: dfs(neighbor) - + # Try to start DFS from each city for i in range(n): if not visited[i]: # New province found res += 1 dfs(i) - - return res + return res diff --git a/solutions/55/01.py b/solutions/55/01.py index 269756f..09eb966 100644 --- a/solutions/55/01.py +++ b/solutions/55/01.py @@ -1,5 +1,6 @@ from typing import List + def canJump(nums: List[int]) -> bool: max_reach = 0 diff --git a/solutions/560/01.py b/solutions/560/01.py index 7d999e4..0ec6d37 100644 --- a/solutions/560/01.py +++ b/solutions/560/01.py @@ -4,15 +4,14 @@ def subarraySum(self, nums: List[int], k: int) -> int: prefix_sum = {0: 1} # sum 0 appears once (empty subarray) current_sum = 0 res = 0 - + for num in nums: current_sum += num # If (current_sum - k) exists in prefix_sum, we found a subarray if current_sum - k in prefix_sum: res += prefix_sum[current_sum - k] - + # Update prefix_sum count prefix_sum[current_sum] = prefix_sum.get(current_sum, 0) + 1 - - return res + return res diff --git a/solutions/57/01.py b/solutions/57/01.py index 5559b83..430bada 100644 --- a/solutions/57/01.py +++ b/solutions/57/01.py @@ -1,23 +1,29 @@ -def insert(intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]: - result = [] +class Solution: + def insert( + self, intervals: List[List[int]], newInterval: List[int] + ) -> List[List[int]]: + res = [] + i = 0 + n = len(intervals) - for interval in intervals: - if interval[1] < newInterval[0]: - result.append(interval) - else: + # Add all intervals that end before newInterval starts + while i < n and intervals[i][1] < newInterval[0]: + res.append(intervals[i]) + i += 1 - start, end = newInterval[0], newInterval[1] - for interval in intervals: - if interval[0] <= end and interval[1] >= start: - # Overlap found, update boundaries - start = min(start, interval[0]) - end = max(end, interval[1]) - elif interval[0] > end: - # No more overlaps, add merged interval and remaining intervals - result.append([start, end]) - result.extend(intervals[intervals.index(interval) :]) - return result + # Merge all overlapping intervals + start, end = newInterval[0], newInterval[1] + while i < n and intervals[i][0] <= end: + start = min(start, intervals[i][0]) + end = max(end, intervals[i][1]) + i += 1 - result.append([start, end]) + # Add the merged interval + res.append([start, end]) - return result + # Add all remaining intervals + while i < n: + res.append(intervals[i]) + i += 1 + + return res diff --git a/solutions/581/01.py b/solutions/581/01.py index 869dded..46e9b98 100644 --- a/solutions/581/01.py +++ b/solutions/581/01.py @@ -1,31 +1,30 @@ class Solution: def findUnsortedSubarray(self, nums: List[int]) -> int: n = len(nums) - + # Find the left boundary: first index where order breaks left = 0 while left < n - 1 and nums[left] <= nums[left + 1]: left += 1 - + if left == n - 1: return 0 # Already sorted - + # Find the right boundary: last index where order breaks right = n - 1 while right > 0 and nums[right] >= nums[right - 1]: right -= 1 - + # Find min and max in the unsorted subarray - sub_min = min(nums[left:right + 1]) - sub_max = max(nums[left:right + 1]) - + sub_min = min(nums[left : right + 1]) + sub_max = max(nums[left : right + 1]) + # Extend left boundary while left > 0 and nums[left - 1] > sub_min: left -= 1 - + # Extend right boundary while right < n - 1 and nums[right + 1] < sub_max: right += 1 - - return right - left + 1 + return right - left + 1 diff --git a/solutions/6/01.py b/solutions/6/01.py index 16db48b..3827fa4 100644 --- a/solutions/6/01.py +++ b/solutions/6/01.py @@ -2,24 +2,23 @@ class Solution: def convert(self, s: str, numRows: int) -> str: if numRows == 1: return s - + # Create rows to store characters rows = [""] * numRows current_row = 0 going_down = False - + # Distribute characters into rows for char in s: rows[current_row] += char - + # Change direction at top or bottom if current_row == 0 or current_row == numRows - 1: going_down = not going_down - + # Move to next row current_row += 1 if going_down else -1 - + # Concatenate all rows res = "".join(rows) return res - diff --git a/solutions/605/01.py b/solutions/605/01.py index 7c9ad27..591cc59 100644 --- a/solutions/605/01.py +++ b/solutions/605/01.py @@ -1,17 +1,22 @@ from typing import List + class Solution: def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool: count = 0 i = 0 - + while i < len(flowerbed): # Check if current plot and adjacent plots are empty - if flowerbed[i] == 0 and (i == 0 or flowerbed[i - 1] == 0) and (i == len(flowerbed) - 1 or flowerbed[i + 1] == 0): + if ( + flowerbed[i] == 0 + and (i == 0 or flowerbed[i - 1] == 0) + and (i == len(flowerbed) - 1 or flowerbed[i + 1] == 0) + ): flowerbed[i] = 1 count += 1 i += 2 # Skip next plot since we can't plant adjacent else: i += 1 - + return count >= n diff --git a/solutions/617/01.py b/solutions/617/01.py index 7717c64..e3b3cb0 100644 --- a/solutions/617/01.py +++ b/solutions/617/01.py @@ -5,22 +5,23 @@ # self.left = left # self.right = right class Solution: - def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: + def mergeTrees( + self, root1: Optional[TreeNode], root2: Optional[TreeNode] + ) -> Optional[TreeNode]: if not root1 and not root2: return None - + if not root1: return root2 - + if not root2: return root1 - + # Merge values merged = TreeNode(root1.val + root2.val) - + # Recursively merge left and right subtrees merged.left = self.mergeTrees(root1.left, root2.left) merged.right = self.mergeTrees(root1.right, root2.right) - - return merged + return merged diff --git a/solutions/62/01.py b/solutions/62/01.py index 6eb33ec..e90916e 100644 --- a/solutions/62/01.py +++ b/solutions/62/01.py @@ -2,11 +2,10 @@ class Solution: def uniquePaths(self, m: int, n: int) -> int: # Create DP table dp = [[1] * n for _ in range(m)] - + # Fill the table for i in range(1, m): for j in range(1, n): dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - - return dp[m - 1][n - 1] + return dp[m - 1][n - 1] diff --git a/solutions/637/01.py b/solutions/637/01.py index 741ca82..4bb4b9d 100644 --- a/solutions/637/01.py +++ b/solutions/637/01.py @@ -6,28 +6,28 @@ # self.right = right from collections import deque + class Solution: def averageOfLevels(self, root: Optional[TreeNode]) -> List[float]: if not root: return [] - + queue = deque([root]) res = [] - + while queue: level_size = len(queue) level_sum = 0 - + for _ in range(level_size): node = queue.popleft() level_sum += node.val - + if node.left: queue.append(node.left) if node.right: queue.append(node.right) - + res.append(level_sum / level_size) - - return res + return res diff --git a/solutions/64/01.py b/solutions/64/01.py index b3749f6..02af4b0 100644 --- a/solutions/64/01.py +++ b/solutions/64/01.py @@ -1,28 +1,28 @@ from typing import List + class Solution: def minPathSum(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) - + # dp[i][j] represents minimum path sum to reach (i, j) dp = [[0] * n for _ in range(m)] - + # Base case: starting position dp[0][0] = grid[0][0] - + # Fill first row: can only come from left for j in range(1, n): - dp[0][j] = dp[0][j-1] + grid[0][j] - + dp[0][j] = dp[0][j - 1] + grid[0][j] + # Fill first column: can only come from top for i in range(1, m): - dp[i][0] = dp[i-1][0] + grid[i][0] - + dp[i][0] = dp[i - 1][0] + grid[i][0] + # Fill remaining cells for i in range(1, m): for j in range(1, n): # Can come from top or left, choose minimum - dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j] - - return dp[m-1][n-1] + dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j] + return dp[m - 1][n - 1] diff --git a/solutions/643/01.py b/solutions/643/01.py index 054180f..00d9e79 100644 --- a/solutions/643/01.py +++ b/solutions/643/01.py @@ -1,14 +1,15 @@ from typing import List + class Solution: def findMaxAverage(self, nums: List[int], k: int) -> float: # Calculate sum of first window window_sum = sum(nums[:k]) max_sum = window_sum - + # Slide the window for i in range(k, len(nums)): window_sum = window_sum - nums[i - k] + nums[i] max_sum = max(max_sum, window_sum) - + return max_sum / k diff --git a/solutions/649/01.py b/solutions/649/01.py index d269219..05e2f5c 100644 --- a/solutions/649/01.py +++ b/solutions/649/01.py @@ -2,23 +2,22 @@ class Solution: def predictPartyVictory(self, senate: str) -> str: r_queue = [] d_queue = [] - + for i, party in enumerate(senate): - if party == 'R': + if party == "R": r_queue.append(i) else: d_queue.append(i) - + n = len(senate) - + while r_queue and d_queue: r_idx = r_queue.pop(0) d_idx = d_queue.pop(0) - + if r_idx < d_idx: r_queue.append(r_idx + n) else: d_queue.append(d_idx + n) - - return "Radiant" if r_queue else "Dire" + return "Radiant" if r_queue else "Dire" diff --git a/solutions/66/01.py b/solutions/66/01.py index 050a35e..fa95f7b 100644 --- a/solutions/66/01.py +++ b/solutions/66/01.py @@ -1,5 +1,6 @@ from typing import List + class Solution: def plusOne(self, digits: List[int]) -> List[int]: # Start from the rightmost digit @@ -10,6 +11,6 @@ def plusOne(self, digits: List[int]) -> List[int]: return digits # Otherwise, set to 0 and continue (carry over) digits[i] = 0 - + # If we reach here, all digits were 9, need to add 1 at the beginning return [1] + digits diff --git a/solutions/67/01.py b/solutions/67/01.py index 7fb4aff..864bd63 100644 --- a/solutions/67/01.py +++ b/solutions/67/01.py @@ -1,4 +1,4 @@ -def addBinary( a: str, b: str) -> str: +def addBinary(a: str, b: str) -> str: result = "" carry = 0 i, j = len(a) - 1, len(b) - 1 diff --git a/solutions/695/01.py b/solutions/695/01.py index 4080226..3a65673 100644 --- a/solutions/695/01.py +++ b/solutions/695/01.py @@ -2,26 +2,25 @@ class Solution: def maxAreaOfIsland(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) res = 0 - + def dfs(i, j): if i < 0 or i >= m or j < 0 or j >= n or grid[i][j] == 0: return 0 - + grid[i][j] = 0 # Mark as visited area = 1 - + # Explore 4 directions area += dfs(i + 1, j) area += dfs(i - 1, j) area += dfs(i, j + 1) area += dfs(i, j - 1) - + return area - + for i in range(m): for j in range(n): if grid[i][j] == 1: res = max(res, dfs(i, j)) - - return res + return res diff --git a/solutions/7/01.py b/solutions/7/01.py index e71f3cb..9cf749e 100644 --- a/solutions/7/01.py +++ b/solutions/7/01.py @@ -3,19 +3,18 @@ def reverse(self, x: int) -> int: # Handle negative numbers sign = -1 if x < 0 else 1 x = abs(x) - + # Reverse the digits reversed_num = 0 while x > 0: reversed_num = reversed_num * 10 + x % 10 x //= 10 - + # Apply sign and check for overflow result = sign * reversed_num - + # Check 32-bit integer bounds - if result < -2**31 or result > 2**31 - 1: + if result < -(2**31) or result > 2**31 - 1: return 0 - - return result + return result diff --git a/solutions/700/01.py b/solutions/700/01.py index cc9ed8d..717a2e3 100644 --- a/solutions/700/01.py +++ b/solutions/700/01.py @@ -8,11 +8,10 @@ class Solution: def searchBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]: if not root: return None - + if root.val == val: return root elif root.val > val: return self.searchBST(root.left, val) else: return self.searchBST(root.right, val) - diff --git a/solutions/701/01.py b/solutions/701/01.py index 20b67fc..b9da6b3 100644 --- a/solutions/701/01.py +++ b/solutions/701/01.py @@ -5,18 +5,18 @@ # self.left = left # self.right = right + class Solution: def insertIntoBST(self, root, val: int): # If tree is empty, create new node if not root: return TreeNode(val) - + # If val is less than root, insert into left subtree if val < root.val: root.left = self.insertIntoBST(root.left, val) # If val is greater than root, insert into right subtree else: root.right = self.insertIntoBST(root.right, val) - - return root + return root diff --git a/solutions/704/01.py b/solutions/704/01.py index 5629774..451b641 100644 --- a/solutions/704/01.py +++ b/solutions/704/01.py @@ -1,29 +1,28 @@ from typing import List + class Solution: def search(self, nums: List[int], target: int) -> int: # Initialize left and right pointers left = 0 right = len(nums) - 1 - + # Binary search while left <= right: # Calculate middle index mid = (left + right) // 2 - + # If target found at mid if nums[mid] == target: return mid - + # If target is smaller, search left half elif nums[mid] > target: right = mid - 1 - + # If target is larger, search right half else: left = mid + 1 - + # Target not found return -1 - - diff --git a/solutions/71/01.py b/solutions/71/01.py index 927106e..d41238e 100644 --- a/solutions/71/01.py +++ b/solutions/71/01.py @@ -1,21 +1,21 @@ class Solution: def simplifyPath(self, path: str) -> str: # Split path by '/' and filter out empty strings - parts = [p for p in path.split('/') if p] + parts = [p for p in path.split("/") if p] stack = [] - + for part in parts: - if part == '.': + if part == ".": # Current directory, do nothing continue - elif part == '..': + elif part == "..": # Parent directory, go up one level if stack: stack.pop() else: # Valid directory or file name stack.append(part) - + # Construct result path - res = '/' + '/'.join(stack) + res = "/" + "/".join(stack) return res diff --git a/solutions/714/01.py b/solutions/714/01.py index 5b33f16..19b1b85 100644 --- a/solutions/714/01.py +++ b/solutions/714/01.py @@ -2,10 +2,9 @@ class Solution: def maxProfit(self, prices: List[int], fee: int) -> int: hold = -prices[0] sold = 0 - + for i in range(1, len(prices)): hold = max(hold, sold - prices[i]) sold = max(sold, hold + prices[i] - fee) - - return sold + return sold diff --git a/solutions/72/01.py b/solutions/72/01.py index 0870881..636d361 100644 --- a/solutions/72/01.py +++ b/solutions/72/01.py @@ -1,16 +1,16 @@ class Solution: def minDistance(self, word1: str, word2: str) -> int: m, n = len(word1), len(word2) - + # dp[i][j] represents the minimum operations to convert word1[0:i] to word2[0:j] dp = [[0] * (n + 1) for _ in range(m + 1)] - + # Base cases for i in range(m + 1): dp[i][0] = i # Delete all characters from word1 for j in range(n + 1): dp[0][j] = j # Insert all characters to word1 - + # Fill the DP table for i in range(1, m + 1): for j in range(1, n + 1): @@ -20,10 +20,9 @@ def minDistance(self, word1: str, word2: str) -> int: else: # Try three operations: insert, delete, replace dp[i][j] = 1 + min( - dp[i][j - 1], # Insert - dp[i - 1][j], # Delete - dp[i - 1][j - 1] # Replace + dp[i][j - 1], # Insert + dp[i - 1][j], # Delete + dp[i - 1][j - 1], # Replace ) - - return dp[m][n] + return dp[m][n] diff --git a/solutions/724/01.py b/solutions/724/01.py index 15e89ba..2b9c566 100644 --- a/solutions/724/01.py +++ b/solutions/724/01.py @@ -1,26 +1,25 @@ from typing import List + class Solution: def pivotIndex(self, nums: List[int]) -> int: # Calculate total sum of the array total_sum = sum(nums) - + # Track left sum as we iterate left_sum = 0 - + # Iterate through each index for i in range(len(nums)): # Right sum = total sum - left sum - current element right_sum = total_sum - left_sum - nums[i] - + # Check if left sum equals right sum if left_sum == right_sum: return i - + # Add current element to left sum for next iteration left_sum += nums[i] - + # No pivot index found return -1 - - diff --git a/solutions/73/01.py b/solutions/73/01.py index 784593a..fad0354 100644 --- a/solutions/73/01.py +++ b/solutions/73/01.py @@ -5,50 +5,50 @@ def setZeroes(self, matrix: List[List[int]]) -> None: if not matrix or not matrix[0]: return - + m, n = len(matrix), len(matrix[0]) - + # Use first row and column as markers # We need to handle them separately since they're used as markers first_row_has_zero = False first_col_has_zero = False - + # Check if first row has any zeros for j in range(n): if matrix[0][j] == 0: first_row_has_zero = True break - + # Check if first column has any zeros for i in range(m): if matrix[i][0] == 0: first_col_has_zero = True break - + # Use first row and column as markers for other elements for i in range(1, m): for j in range(1, n): if matrix[i][j] == 0: matrix[i][0] = 0 # Mark row i matrix[0][j] = 0 # Mark column j - + # Set rows to zero based on markers (excluding first row) for i in range(1, m): if matrix[i][0] == 0: for j in range(1, n): matrix[i][j] = 0 - + # Set columns to zero based on markers (excluding first column) for j in range(1, n): if matrix[0][j] == 0: for i in range(1, m): matrix[i][j] = 0 - + # Handle first row if first_row_has_zero: for j in range(n): matrix[0][j] = 0 - + # Handle first column if first_col_has_zero: for i in range(m): diff --git a/solutions/733/01.py b/solutions/733/01.py index c97f1f0..7a5dd3d 100644 --- a/solutions/733/01.py +++ b/solutions/733/01.py @@ -1,32 +1,34 @@ from typing import List + class Solution: - def floodFill(self, image: List[List[int]], sr: int, sc: int, color: int) -> List[List[int]]: + def floodFill( + self, image: List[List[int]], sr: int, sc: int, color: int + ) -> List[List[int]]: # Original color at starting position original_color = image[sr][sc] - + # If original color is same as new color, no change needed if original_color == color: return image - + m, n = len(image), len(image[0]) - + def dfs(r, c): # Check bounds and if pixel has original color if r < 0 or r >= m or c < 0 or c >= n or image[r][c] != original_color: return - + # Change color image[r][c] = color - + # Recursively fill adjacent pixels (4-directional) dfs(r - 1, c) # up dfs(r + 1, c) # down dfs(r, c - 1) # left dfs(r, c + 1) # right - + # Start flood fill from starting position dfs(sr, sc) - - return image + return image diff --git a/solutions/735/01.py b/solutions/735/01.py index 31f2224..bec2941 100644 --- a/solutions/735/01.py +++ b/solutions/735/01.py @@ -1,7 +1,7 @@ class Solution: def asteroidCollision(self, asteroids: List[int]) -> List[int]: res = [] - + for asteroid in asteroids: while res and asteroid < 0 < res[-1]: if res[-1] < -asteroid: @@ -12,6 +12,5 @@ def asteroidCollision(self, asteroids: List[int]) -> List[int]: break else: res.append(asteroid) - - return res + return res diff --git a/solutions/74/01.py b/solutions/74/01.py index b4e3799..b83180d 100644 --- a/solutions/74/01.py +++ b/solutions/74/01.py @@ -1,26 +1,26 @@ from typing import List + class Solution: def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: m, n = len(matrix), len(matrix[0]) - + # Binary search on the flattened matrix left = 0 right = m * n - 1 - + while left <= right: mid = (left + right) // 2 # Convert 1D index to 2D coordinates row = mid // n col = mid % n mid_value = matrix[row][col] - + if mid_value == target: return True elif mid_value < target: left = mid + 1 else: right = mid - 1 - - return False + return False diff --git a/solutions/746/01.py b/solutions/746/01.py index 8e02d29..565b34d 100644 --- a/solutions/746/01.py +++ b/solutions/746/01.py @@ -1,21 +1,21 @@ from typing import List + class Solution: def minCostClimbingStairs(self, cost: List[int]) -> int: n = len(cost) - + # dp[i] represents minimum cost to reach step i dp = [0] * (n + 1) - + # Base cases: can start at step 0 or step 1 with cost 0 dp[0] = 0 dp[1] = 0 - + # Fill dp array for i in range(2, n + 1): # Can reach step i from step i-1 or step i-2 # Add the cost of the step we're leaving dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]) - - return dp[n] + return dp[n] diff --git a/solutions/75/01.py b/solutions/75/01.py index bd10dc1..12923b5 100644 --- a/solutions/75/01.py +++ b/solutions/75/01.py @@ -1,12 +1,13 @@ from typing import List + class Solution: def sortColors(self, nums: List[int]) -> None: # Dutch National Flag algorithm left = 0 # Points to the end of 0s right = len(nums) - 1 # Points to the start of 2s i = 0 # Current pointer - + while i <= right: if nums[i] == 0: # Swap with left pointer @@ -21,4 +22,3 @@ def sortColors(self, nums: List[int]) -> None: else: # nums[i] == 1, just move forward i += 1 - diff --git a/solutions/76/01.py b/solutions/76/01.py index fadcac2..da27b38 100644 --- a/solutions/76/01.py +++ b/solutions/76/01.py @@ -2,45 +2,44 @@ class Solution: def minWindow(self, s: str, t: str) -> str: if not s or not t: return "" - + # Count characters in t need = {} for char in t: need[char] = need.get(char, 0) + 1 - + # Sliding window left = 0 right = 0 window = {} valid = 0 # Number of characters in window that satisfy need start = 0 - min_len = float('inf') - + min_len = float("inf") + while right < len(s): # Expand window char = s[right] right += 1 - + if char in need: window[char] = window.get(char, 0) + 1 if window[char] == need[char]: valid += 1 - + # Shrink window when all characters are satisfied while valid == len(need): # Update minimum window if right - left < min_len: min_len = right - left start = left - + # Remove left character char_left = s[left] left += 1 - + if char_left in need: if window[char_left] == need[char_left]: valid -= 1 window[char_left] -= 1 - - return "" if min_len == float('inf') else s[start:start + min_len] + return "" if min_len == float("inf") else s[start : start + min_len] diff --git a/solutions/77/01.py b/solutions/77/01.py index 90a5f46..6b4387d 100644 --- a/solutions/77/01.py +++ b/solutions/77/01.py @@ -1,21 +1,21 @@ from typing import List + class Solution: def combine(self, n: int, k: int) -> List[List[int]]: res = [] - + def backtrack(start, current_combination): # Base case: combination of size k found if len(current_combination) == k: res.append(current_combination[:]) return - + # Try each number from start to n for i in range(start, n + 1): current_combination.append(i) backtrack(i + 1, current_combination) current_combination.pop() # Backtrack - + backtrack(1, []) return res - diff --git a/solutions/78/01.py b/solutions/78/01.py index 8329a5c..734e42f 100644 --- a/solutions/78/01.py +++ b/solutions/78/01.py @@ -1,19 +1,19 @@ from typing import List + class Solution: def subsets(self, nums: List[int]) -> List[List[int]]: res = [] - + def backtrack(index, current_subset): # Add current subset to result res.append(current_subset[:]) - + # Try adding each remaining element for i in range(index, len(nums)): current_subset.append(nums[i]) backtrack(i + 1, current_subset) current_subset.pop() - + backtrack(0, []) return res - diff --git a/solutions/79/01.py b/solutions/79/01.py index c43327c..a9a863c 100644 --- a/solutions/79/01.py +++ b/solutions/79/01.py @@ -1,38 +1,43 @@ from typing import List + class Solution: def exist(self, board: List[List[str]], word: str) -> bool: m, n = len(board), len(board[0]) - + def dfs(row, col, index): # Base case: found the word if index == len(word): return True - + # Check bounds and if current cell matches - if (row < 0 or row >= m or col < 0 or col >= n or - board[row][col] != word[index]): + if ( + row < 0 + or row >= m + or col < 0 + or col >= n + or board[row][col] != word[index] + ): return False - + # Mark current cell as visited temp = board[row][col] - board[row][col] = '#' - + board[row][col] = "#" + # Explore 4 directions directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] for dr, dc in directions: if dfs(row + dr, col + dc, index + 1): return True - + # Backtrack: restore cell board[row][col] = temp return False - + # Try starting from each cell for i in range(m): for j in range(n): if dfs(i, j, 0): return True - - return False + return False diff --git a/solutions/790/01.py b/solutions/790/01.py index 6009d96..604746a 100644 --- a/solutions/790/01.py +++ b/solutions/790/01.py @@ -2,15 +2,14 @@ class Solution: def numTilings(self, n: int) -> int: if n <= 2: return n - + MOD = 10**9 + 7 dp = [0] * (n + 1) dp[0] = 1 dp[1] = 1 dp[2] = 2 - + for i in range(3, n + 1): dp[i] = (2 * dp[i - 1] + dp[i - 3]) % MOD - - return dp[n] + return dp[n] diff --git a/solutions/797/01.py b/solutions/797/01.py index 9f041f3..68433e3 100644 --- a/solutions/797/01.py +++ b/solutions/797/01.py @@ -2,16 +2,16 @@ class Solution: def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]: res = [] n = len(graph) - + def dfs(node, path): if node == n - 1: res.append(path[:]) return - + for neighbor in graph[node]: path.append(neighbor) dfs(neighbor, path) path.pop() - + dfs(0, [0]) return res diff --git a/solutions/82/01.py b/solutions/82/01.py index 9128344..cd7fe32 100644 --- a/solutions/82/01.py +++ b/solutions/82/01.py @@ -8,10 +8,10 @@ def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: # Create a dummy node to handle edge cases dummy = ListNode(0) dummy.next = head - + prev = dummy curr = head - + while curr and curr.next: # If we find duplicates if curr.val == curr.next.val: @@ -25,6 +25,5 @@ def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: # No duplicates, move both pointers prev = curr curr = curr.next - - return dummy.next + return dummy.next diff --git a/solutions/84/01.py b/solutions/84/01.py index a8045b9..a5500ce 100644 --- a/solutions/84/01.py +++ b/solutions/84/01.py @@ -1,10 +1,11 @@ from typing import List + class Solution: def largestRectangleArea(self, heights: List[int]) -> int: stack = [] # Stack of indices max_area = 0 - + for i, height in enumerate(heights): # While current height is less than stack top, calculate area while stack and heights[stack[-1]] > height: @@ -12,12 +13,11 @@ def largestRectangleArea(self, heights: List[int]) -> int: width = i if not stack else i - stack[-1] - 1 max_area = max(max_area, h * width) stack.append(i) - + # Process remaining bars in stack while stack: h = heights[stack.pop()] width = len(heights) if not stack else len(heights) - stack[-1] - 1 max_area = max(max_area, h * width) - - return max_area + return max_area diff --git a/solutions/841/01.py b/solutions/841/01.py index bfbcf40..bba8a20 100644 --- a/solutions/841/01.py +++ b/solutions/841/01.py @@ -1,19 +1,19 @@ from typing import List + class Solution: def canVisitAllRooms(self, rooms: List[List[int]]) -> bool: n = len(rooms) visited = [False] * n - + def dfs(room): visited[room] = True for key in rooms[room]: if not visited[key]: dfs(key) - + # Start from room 0 dfs(0) - + # Check if all rooms are visited return all(visited) - diff --git a/solutions/86/01.py b/solutions/86/01.py index 317abaa..573c3d0 100644 --- a/solutions/86/01.py +++ b/solutions/86/01.py @@ -8,12 +8,12 @@ def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]: # Create two dummy nodes for less than x and greater than or equal to x less_head = ListNode(0) greater_head = ListNode(0) - + less = less_head greater = greater_head - + curr = head - + while curr: if curr.val < x: less.next = curr @@ -22,10 +22,9 @@ def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]: greater.next = curr greater = greater.next curr = curr.next - + # Connect the two partitions less.next = greater_head.next greater.next = None # Important: break the chain - - return less_head.next + return less_head.next diff --git a/solutions/872/01.py b/solutions/872/01.py index 2c140ff..457405c 100644 --- a/solutions/872/01.py +++ b/solutions/872/01.py @@ -12,6 +12,5 @@ def get_leaves(node): if not node.left and not node.right: return [node.val] return get_leaves(node.left) + get_leaves(node.right) - - return get_leaves(root1) == get_leaves(root2) + return get_leaves(root1) == get_leaves(root2) diff --git a/solutions/875/01.py b/solutions/875/01.py index 98f3763..e69f2f1 100644 --- a/solutions/875/01.py +++ b/solutions/875/01.py @@ -2,16 +2,15 @@ class Solution: def minEatingSpeed(self, piles: List[int], h: int) -> int: left, right = 1, max(piles) res = right - + while left <= right: mid = (left + right) // 2 hours = sum((pile + mid - 1) // mid for pile in piles) - + if hours <= h: res = mid right = mid - 1 else: left = mid + 1 - - return res + return res diff --git a/solutions/876/01.py b/solutions/876/01.py index 37dcd90..02dc943 100644 --- a/solutions/876/01.py +++ b/solutions/876/01.py @@ -4,15 +4,16 @@ # self.val = val # self.next = next + class Solution: def middleNode(self, head): slow = head fast = head - + # Move fast pointer twice as fast as slow pointer while fast and fast.next: slow = slow.next fast = fast.next.next - + # When fast reaches the end, slow is at the middle return slow diff --git a/solutions/89/01.py b/solutions/89/01.py index 36f9236..2a9a19e 100644 --- a/solutions/89/01.py +++ b/solutions/89/01.py @@ -1,28 +1,28 @@ def grayCode(n): """ Generate an n-bit Gray code sequence. - + Args: n: int - Number of bits for the Gray code sequence - + Returns: List[int] - Valid n-bit Gray code sequence """ # Handle edge case if n == 0: return [0] - + # Start with base case: 1-bit Gray code result = [0, 1] - + # Build larger Gray codes using reflection method for i in range(2, n + 1): # Get the size of the current sequence size = len(result) - + # Reflect the current sequence and add prefix '1' for j in range(size - 1, -1, -1): # Add 2^(i-1) to create the reflected part with prefix '1' result.append(result[j] + (1 << (i - 1))) - + return result diff --git a/solutions/9/01.py b/solutions/9/01.py index 547a028..9a44639 100644 --- a/solutions/9/01.py +++ b/solutions/9/01.py @@ -3,16 +3,15 @@ def isPalindrome(self, x: int) -> bool: # Negative numbers are not palindromes if x < 0: return False - + # Reverse the number original = x reversed_num = 0 - + while x > 0: reversed_num = reversed_num * 10 + x % 10 x //= 10 - + # Compare original with reversed res = original == reversed_num return res - diff --git a/solutions/909/01.py b/solutions/909/01.py index 5e1cffb..d2a43aa 100644 --- a/solutions/909/01.py +++ b/solutions/909/01.py @@ -1,9 +1,10 @@ from collections import deque + class Solution: def snakesAndLadders(self, board: List[List[int]]) -> int: n = len(board) - + def get_position(square): # Convert square number to row, col row = (square - 1) // n @@ -12,27 +13,26 @@ def get_position(square): col = n - 1 - col row = n - 1 - row # Board is bottom-up return row, col - + queue = deque([(1, 0)]) # (square, moves) visited = {1} - + while queue: square, moves = queue.popleft() - + if square == n * n: return moves - + # Try all 6 possible moves for next_square in range(square + 1, min(square + 7, n * n + 1)): row, col = get_position(next_square) - + # Check if there's a snake or ladder if board[row][col] != -1: next_square = board[row][col] - + if next_square not in visited: visited.add(next_square) queue.append((next_square, moves + 1)) - - return -1 + return -1 diff --git a/solutions/918/01.py b/solutions/918/01.py index a59dce6..cb78553 100644 --- a/solutions/918/01.py +++ b/solutions/918/01.py @@ -1,32 +1,32 @@ from typing import List + class Solution: def maxSubarraySumCircular(self, nums: List[int]) -> int: # Case 1: Maximum subarray is in the middle (normal case) max_sum = nums[0] current_max = 0 - + # Case 2: Maximum subarray wraps around (circular) # This means we want to minimize the middle part min_sum = nums[0] current_min = 0 total_sum = 0 - + for num in nums: # Normal maximum subarray current_max = max(current_max + num, num) max_sum = max(max_sum, current_max) - + # Minimum subarray (for circular case) current_min = min(current_min + num, num) min_sum = min(min_sum, current_min) - + total_sum += num - + # If all numbers are negative, return max_sum if max_sum < 0: return max_sum - + # Return max of normal case and circular case return max(max_sum, total_sum - min_sum) - diff --git a/solutions/92/01.py b/solutions/92/01.py index 89f459c..35ec5d0 100644 --- a/solutions/92/01.py +++ b/solutions/92/01.py @@ -1,24 +1,27 @@ from typing import Optional + # Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: - def reverseBetween(self, head: Optional[ListNode], left: int, right: int) -> Optional[ListNode]: + def reverseBetween( + self, head: Optional[ListNode], left: int, right: int + ) -> Optional[ListNode]: if not head or left == right: return head - + # Create dummy node to handle edge case when left = 1 dummy = ListNode(0) dummy.next = head prev = dummy - + # Move to the node before the reversal starts for _ in range(left - 1): prev = prev.next - + # Reverse the segment curr = prev.next for _ in range(right - left): @@ -26,6 +29,5 @@ def reverseBetween(self, head: Optional[ListNode], left: int, right: int) -> Opt curr.next = next_node.next next_node.next = prev.next prev.next = next_node - - return dummy.next + return dummy.next diff --git a/solutions/933/01.py b/solutions/933/01.py index a758197..0b22a15 100644 --- a/solutions/933/01.py +++ b/solutions/933/01.py @@ -1,5 +1,6 @@ from collections import deque + class RecentCounter: def __init__(self): self.queue = deque() @@ -7,11 +8,10 @@ def __init__(self): def ping(self, t: int) -> int: # Add current request time self.queue.append(t) - + # Remove requests outside the 3000ms window while self.queue[0] < t - 3000: self.queue.popleft() - + # Return number of requests in the window return len(self.queue) - diff --git a/solutions/94/01.py b/solutions/94/01.py index 54a55fd..34b1720 100644 --- a/solutions/94/01.py +++ b/solutions/94/01.py @@ -7,17 +7,17 @@ from typing import List + class Solution: def inorderTraversal(self, root) -> List[int]: res = [] - + def inorder(node): if not node: return inorder(node.left) res.append(node.val) inorder(node.right) - + inorder(root) return res - diff --git a/solutions/944/01.py b/solutions/944/01.py index fe99dfe..aa74ca4 100644 --- a/solutions/944/01.py +++ b/solutions/944/01.py @@ -3,7 +3,7 @@ def minDeletionSize(self, strs: List[str]) -> int: n = len(strs) m = len(strs[0]) res = 0 - + # Check each column for col in range(m): # Check if column is sorted @@ -11,6 +11,5 @@ def minDeletionSize(self, strs: List[str]) -> int: if strs[row][col] < strs[row - 1][col]: res += 1 break - - return res + return res diff --git a/solutions/955/01.py b/solutions/955/01.py new file mode 100644 index 0000000..4356fac --- /dev/null +++ b/solutions/955/01.py @@ -0,0 +1,24 @@ +class Solution: + def minDeletionSize(self, strs: List[str]) -> int: + n = len(strs) + m = len(strs[0]) + res = 0 + # Track which pairs of strings are already sorted + sorted_pairs = [False] * (n - 1) + + for j in range(m): + # Check if this column breaks any unsorted pair + should_delete = False + for i in range(n - 1): + if not sorted_pairs[i] and strs[i][j] > strs[i + 1][j]: + res += 1 + should_delete = True + break + + # If we keep this column, update sorted status + if not should_delete: + for i in range(n - 1): + if strs[i][j] < strs[i + 1][j]: + sorted_pairs[i] = True + + return res diff --git a/solutions/97/01.py b/solutions/97/01.py index 4e43d8d..559ed99 100644 --- a/solutions/97/01.py +++ b/solutions/97/01.py @@ -2,25 +2,25 @@ class Solution: def isInterleave(self, s1: str, s2: str, s3: str) -> bool: if len(s1) + len(s2) != len(s3): return False - + m, n = len(s1), len(s2) # dp[i][j] = True if s1[:i] and s2[:j] can form s3[:i+j] dp = [[False] * (n + 1) for _ in range(m + 1)] dp[0][0] = True - + # Fill first row: using only s2 for j in range(1, n + 1): dp[0][j] = dp[0][j - 1] and s2[j - 1] == s3[j - 1] - + # Fill first column: using only s1 for i in range(1, m + 1): dp[i][0] = dp[i - 1][0] and s1[i - 1] == s3[i - 1] - + # Fill the rest for i in range(1, m + 1): for j in range(1, n + 1): - dp[i][j] = (dp[i - 1][j] and s1[i - 1] == s3[i + j - 1]) or \ - (dp[i][j - 1] and s2[j - 1] == s3[i + j - 1]) - - return dp[m][n] + dp[i][j] = (dp[i - 1][j] and s1[i - 1] == s3[i + j - 1]) or ( + dp[i][j - 1] and s2[j - 1] == s3[i + j - 1] + ) + return dp[m][n] diff --git a/solutions/973/01.py b/solutions/973/01.py index 8e6d506..122eb44 100644 --- a/solutions/973/01.py +++ b/solutions/973/01.py @@ -3,9 +3,8 @@ def kClosest(self, points: List[List[int]], k: int) -> List[List[int]]: # Calculate distance squared (no need for sqrt) def distance_sq(point): return point[0] ** 2 + point[1] ** 2 - + # Sort by distance points.sort(key=distance_sq) - - return points[:k] + return points[:k] diff --git a/solutions/98/01.py b/solutions/98/01.py index e3133c8..2707961 100644 --- a/solutions/98/01.py +++ b/solutions/98/01.py @@ -5,20 +5,21 @@ # self.left = left # self.right = right + class Solution: def isValidBST(self, root) -> bool: def validate(node, min_val, max_val): # Empty tree is valid if not node: return True - + # Check if current node value is within valid range if node.val <= min_val or node.val >= max_val: return False - + # Recursively validate left and right subtrees - return (validate(node.left, min_val, node.val) and - validate(node.right, node.val, max_val)) - - return validate(root, float('-inf'), float('inf')) + return validate(node.left, min_val, node.val) and validate( + node.right, node.val, max_val + ) + return validate(root, float("-inf"), float("inf")) diff --git a/solutions/981/01.py b/solutions/981/01.py index 3aad378..696885e 100644 --- a/solutions/981/01.py +++ b/solutions/981/01.py @@ -11,12 +11,12 @@ def set(self, key: str, value: str, timestamp: int) -> None: def get(self, key: str, timestamp: int) -> str: if key not in self.store: return "" - + # Binary search for the largest timestamp <= given timestamp values = self.store[key] left, right = 0, len(values) - 1 res = "" - + while left <= right: mid = (left + right) // 2 if values[mid][0] <= timestamp: @@ -24,6 +24,5 @@ def get(self, key: str, timestamp: int) -> str: left = mid + 1 else: right = mid - 1 - - return res + return res diff --git a/solutions/994/01.py b/solutions/994/01.py index 90e595e..ca2d89e 100644 --- a/solutions/994/01.py +++ b/solutions/994/01.py @@ -1,12 +1,13 @@ from typing import List from collections import deque + class Solution: def orangesRotting(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) queue = deque() fresh_count = 0 - + # Find all rotten oranges and count fresh oranges for i in range(m): for j in range(n): @@ -14,30 +15,29 @@ def orangesRotting(self, grid: List[List[int]]) -> int: queue.append((i, j, 0)) # (row, col, time) elif grid[i][j] == 1: fresh_count += 1 - + # If no fresh oranges, return 0 if fresh_count == 0: return 0 - + directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] max_time = 0 - + # BFS to rot oranges while queue: r, c, time = queue.popleft() max_time = max(max_time, time) - + # Check all 4 directions for dr, dc in directions: nr, nc = r + dr, c + dc - + # Check bounds and if orange is fresh if 0 <= nr < m and 0 <= nc < n and grid[nr][nc] == 1: # Rot the orange grid[nr][nc] = 2 fresh_count -= 1 queue.append((nr, nc, time + 1)) - + # If there are still fresh oranges, return -1 return max_time if fresh_count == 0 else -1 - diff --git a/solutions/997/01.py b/solutions/997/01.py index 365497d..f2efbb7 100644 --- a/solutions/997/01.py +++ b/solutions/997/01.py @@ -1,21 +1,21 @@ from typing import List + class Solution: def findJudge(self, n: int, trust: List[List[int]]) -> int: # Count how many people trust each person trust_count = [0] * (n + 1) # Count how many people each person trusts trusting_count = [0] * (n + 1) - + for a, b in trust: trusting_count[a] += 1 # person a trusts someone - trust_count[b] += 1 # person b is trusted by someone - + trust_count[b] += 1 # person b is trusted by someone + # The judge trusts nobody (trusting_count[i] == 0) # and is trusted by everyone else (trust_count[i] == n - 1) for i in range(1, n + 1): if trusting_count[i] == 0 and trust_count[i] == n - 1: return i - - return -1 + return -1