diff --git a/explanations/3652/en.md b/explanations/3652/en.md new file mode 100644 index 0000000..8e3a9fe --- /dev/null +++ b/explanations/3652/en.md @@ -0,0 +1,61 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** We are given a binary string and can perform two types of operations: flip all characters from index 0 to i (cost: i+1) or flip all characters from index i to n-1 (cost: n-i). We need to find the minimum cost to make all characters equal. + +**1.1 Constraints & Complexity:** + +- **Input Size:** The string length n can be up to 10^5, and each character is either '0' or '1'. +- **Time Complexity:** O(n) - we iterate through the string once to find all transitions. +- **Space Complexity:** O(1) - we only use a constant amount of extra space. +- **Edge Case:** If the string already has all characters equal, there are no transitions and the cost is 0. + +**1.2 High-level approach:** + +The goal is to find the minimum cost to eliminate all transitions (places where adjacent characters differ) in the string. When we encounter a transition, we can either flip the prefix or the suffix, and we choose the cheaper option. + +![String transitions visualization](https://assets.leetcode.com/static_assets/others/string-transitions.png) + +**1.3 Brute force vs. optimized strategy:** + +- **Brute Force:** Try all possible combinations of operations, which would be exponential O(2^n) and too slow. +- **Optimized Strategy:** For each transition at position i, we can either flip [0, i-1] (cost i) or flip [i, n-1] (cost n-i). We choose min(i, n-i) and sum all transition costs. This is O(n) time. +- **Optimization:** By recognizing that each transition can be fixed independently with the cheaper operation, we avoid exponential search and solve in linear time. + +**1.4 Decomposition:** + +1. Iterate through the string from left to right. +2. For each position i, check if there's a transition (s[i] != s[i-1]). +3. If a transition exists, add the minimum cost (min(i, n-i)) to fix it. +4. Return the total cost. + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** + +Let's use the example: `s = "0011"`, `n = 4`. + +- Initialize `res = 0` to track total cost. +- The string has one transition at position 2 (between '0' and '1'). + +**2.2 Start Checking:** + +We iterate through the string starting from index 1, comparing each character with the previous one. + +**2.3 Trace Walkthrough:** + +| Position i | s[i] | s[i-1] | Transition? | Cost Option 1 (flip prefix) | Cost Option 2 (flip suffix) | Chosen Cost | res | +|------------|------|--------|-------------|---------------------------|----------------------------|-------------|-----| +| 1 | '0' | '0' | No | - | - | 0 | 0 | +| 2 | '1' | '0' | Yes | 2 | 2 | 2 | 2 | +| 3 | '1' | '1' | No | - | - | 0 | 2 | + +**2.4 Increment and Loop:** + +After checking all positions, we have found all transitions and calculated the minimum cost to fix each one. + +**2.5 Return Result:** + +The result is 2, which is the minimum cost to make all characters equal. We achieve this by flipping the suffix from index 2 to the end, changing "0011" to "0000". + diff --git a/explanations/3769/en.md b/explanations/3769/en.md index de33934..e5e4419 100644 --- a/explanations/3769/en.md +++ b/explanations/3769/en.md @@ -2,68 +2,60 @@ ### Strategy (The "Why") -**Restate the problem:** We need to sort integers by their binary reflection (reversing binary digits and interpreting as decimal). If two numbers have the same reflection, sort by original value. +**Restate the problem:** We need to sort an array of integers in ascending order based on their binary reflection. The binary reflection of a number is obtained by reversing its binary representation (ignoring leading zeros) and interpreting it as a decimal number. If two numbers have the same binary reflection, the smaller original number should come first. **1.1 Constraints & Complexity:** -- **Input Size:** `1 <= nums.length <= 100`, `1 <= nums[i] <= 10^9` -- **Time Complexity:** O(n log n * log max(nums)) - Sort with comparison function -- **Space Complexity:** O(1) - Sorting in-place -- **Edge Case:** All numbers have same reflection +- **Input Size:** The array length is at most 100, and each number is between 1 and 10^9. +- **Time Complexity:** O(n log n) where n is the array length - we need to sort the array, and each binary reflection calculation is O(log max_value). +- **Space Complexity:** O(n) for the sorted result array. +- **Edge Case:** If all numbers have the same binary reflection, they should be sorted by their original values. **1.2 High-level approach:** -For each number, compute its binary reflection. Sort by reflection value first, then by original value if reflections are equal. +The goal is to compute the binary reflection for each number and use it as the primary sort key, with the original number as the secondary sort key. + +![Binary reflection visualization](https://assets.leetcode.com/static_assets/others/binary-reflection.png) **1.3 Brute force vs. optimized strategy:** -- **Brute Force:** Precompute all reflections, store in separate array, sort indices. This is O(n log n) but uses extra space. -- **Optimized (Custom Sort Key):** Use a key function that computes reflection on-the-fly during sorting. This is O(n log n) with O(1) extra space. -- **Why it's better:** The custom key function is clean and doesn't require precomputation or extra storage. +- **Brute Force:** Manually implement sorting algorithm and binary conversion, which would be more complex. +- **Optimized Strategy:** Use Python's built-in `sorted()` function with a custom key function that returns (binary_reflection, original_value). This leverages efficient sorting algorithms and is O(n log n). +- **Optimization:** Python's Timsort is highly optimized, and using a tuple as the sort key allows us to sort by multiple criteria efficiently. **1.4 Decomposition:** -1. Define function to compute binary reflection -2. Sort array using custom key: (reflection, original_value) -3. Return sorted array +1. Define a helper function to calculate binary reflection: convert to binary string, reverse it, convert back to integer. +2. Sort the array using a key function that returns (binary_reflection, original_value). +3. Return the sorted array. ### Steps (The "How") **2.1 Initialization & Example Setup:** -Let's use the example: `nums = [4,5,4]` - -- Binary reflections: - - 4 → `100` → reversed `001` → 1 - - 5 → `101` → reversed `101` → 5 - - 4 → `100` → reversed `001` → 1 +Let's use the example: `nums = [4, 5, 4]`. -**2.2 Define Binary Reflection Function:** +- Binary representations: 4 = "100", 5 = "101" +- Binary reflections: 4 → "100" reversed → "001" → 1, 5 → "101" reversed → "101" → 5 -```python -def binary_reflection(n): - binary = bin(n)[2:] # Remove '0b' prefix: "100" - reversed_binary = binary[::-1] # "001" - return int(reversed_binary, 2) # 1 -``` +**2.2 Start Processing:** -**2.3 Sort with Custom Key:** +We compute the binary reflection for each number and sort accordingly. -```python -return sorted(nums, key=lambda x: (binary_reflection(x), x)) -``` +**2.3 Trace Walkthrough:** -Sort key is `(reflection, original)`: -- `(1, 4)` for first 4 -- `(5, 5)` for 5 -- `(1, 4)` for second 4 +| Original Number | Binary | Reversed Binary | Reflection Value | Sort Key (reflection, original) | +|-----------------|--------|-----------------|------------------|----------------------------------| +| 4 | "100" | "001" | 1 | (1, 4) | +| 4 | "100" | "001" | 1 | (1, 4) | +| 5 | "101" | "101" | 5 | (5, 5) | -Sorting: `(1, 4) < (1, 4) < (5, 5)` → `[4, 4, 5]` +After sorting by (reflection, original): [(1, 4), (1, 4), (5, 5)] → [4, 4, 5] -**2.4 Return Result:** +**2.4 Increment and Loop:** -The sorted array maintains order: same reflection values are sorted by original value. +The sorting algorithm processes all elements and arranges them according to the sort keys. -**Time Complexity:** O(n log n * log max(nums)) - Sort with O(log max) comparison -**Space Complexity:** O(1) - In-place sort +**2.5 Return Result:** +The result is `[4, 4, 5]`, where numbers with reflection 1 (both 4s) come before the number with reflection 5, and the two 4s maintain their relative order (though they're equal). diff --git a/explanations/3774/en.md b/explanations/3774/en.md index 2017f50..be5856f 100644 --- a/explanations/3774/en.md +++ b/explanations/3774/en.md @@ -2,64 +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 the array. +**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. **1.1 Constraints & Complexity:** -- **Input Size:** `1 <= n <= 100`, `1 <= nums[i] <= 100`, `1 <= k <= n` -- **Time Complexity:** O(n log n) - Sorting dominates -- **Space Complexity:** O(1) - Only using input array -- **Edge Case:** `k = n` means we use all elements +- **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. **1.2 High-level approach:** -Sort the array, then take the `k` largest elements (last `k` elements) and `k` smallest elements (first `k` elements). Calculate the difference between their sums. +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) **1.3 Brute force vs. optimized strategy:** -- **Brute Force:** Find k largest and k smallest without sorting, using multiple passes. This is O(n * k) time. -- **Optimized (Sorting):** Sort once, then directly access first k and last k elements. This is O(n log n) time. -- **Why it's better:** For small arrays (n <= 100), sorting is efficient and makes the solution simple and clear. +- **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. **1.4 Decomposition:** -1. Sort the array in ascending order -2. Sum the first `k` elements (smallest) -3. Sum the last `k` elements (largest) -4. Return absolute difference +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). +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` - -- After sorting: `[2, 2, 4, 5]` - -**2.2 Sort the Array:** +Let's use the example: `nums = [5, 2, 2, 4]`, `k = 2`. -```python -nums.sort() # [2, 2, 4, 5] -``` +- After sorting: `sorted_nums = [2, 2, 4, 5]` -**2.3 Calculate Sum of k Smallest:** +**2.2 Start Processing:** -```python -sum_smallest = sum(nums[:k]) # sum([2, 2]) = 4 -``` +We calculate the sums of the smallest and largest k elements. -**2.4 Calculate Sum of k Largest:** +**2.3 Trace Walkthrough:** -```python -sum_largest = sum(nums[-k:]) # sum([4, 5]) = 9 -``` +| 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 | -**2.5 Return Absolute Difference:** +**2.4 Increment and Loop:** -```python -return abs(sum_largest - sum_smallest) # abs(9 - 4) = 5 -``` +The calculation is straightforward after sorting - no loops needed for the sum calculation. -**Time Complexity:** O(n log n) - Sorting -**Space Complexity:** O(1) - In-place sort +**2.5 Return Result:** +The result is 5, which is the absolute difference between the sum of the 2 largest elements (9) and the sum of the 2 smallest elements (4). diff --git a/explanations/3775/en.md b/explanations/3775/en.md index 5e3f997..1d8d273 100644 --- a/explanations/3775/en.md +++ b/explanations/3775/en.md @@ -2,76 +2,60 @@ ### Strategy (The "Why") -**Restate the problem:** We need to count vowels in the first word, then reverse each following word that has the same vowel count. Leave other words unchanged. +**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. **1.1 Constraints & Complexity:** -- **Input Size:** `1 <= s.length <= 10^5` -- **Time Complexity:** O(n) - Single pass through string -- **Space Complexity:** O(n) - Store words and result -- **Edge Case:** Empty string or single word +- **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. **1.2 High-level approach:** -Split the string into words. Count vowels in the first word. For each subsequent word, if its vowel count matches the first word's count, reverse it. Otherwise, keep it as-is. +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) **1.3 Brute force vs. optimized strategy:** -- **Brute Force:** Multiple passes - one to count vowels in first word, another to process each word. This is still O(n) but less efficient. -- **Optimized (Single Pass):** Split once, count vowels in first word, then process each word in one pass. This is O(n) time. -- **Why it's better:** We process the string efficiently in a single logical pass, making the code clear and maintainable. +- **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. **1.4 Decomposition:** -1. Split string into words -2. Count vowels in first word -3. For each subsequent word: - - Count its vowels - - If count matches first word, reverse it - - Otherwise, keep as-is -4. Join words back into string +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. ### Steps (The "How") **2.1 Initialization & Example Setup:** -Let's use the example: `s = "cat and mice"` - -- Words: `["cat", "and", "mice"]` -- Vowels: `{'a', 'e', 'i', 'o', 'u'}` - -**2.2 Split into Words:** - -```python -words = s.split() # ["cat", "and", "mice"] -``` +Let's use the example: `s = "cat and mice"`. -**2.3 Count Vowels in First Word:** +- Words: ["cat", "and", "mice"] +- First word: "cat" has 1 vowel ('a') -```python -first_vowel_count = sum(1 for c in words[0] if c in vowels) # "cat" has 1 vowel: 'a' -``` +**2.2 Start Processing:** -**2.4 Process Each Subsequent Word:** +We process each word after the first one, checking vowel counts and reversing when needed. -```python -for word in words[1:]: - vowel_count = sum(1 for c in word if c in vowels) - if vowel_count == first_vowel_count: - res.append(word[::-1]) # Reverse - else: - res.append(word) # Keep as-is -``` +**2.3 Trace Walkthrough:** -For `"and"`: vowel_count = 1 (matches), so reverse → `"dna"` -For `"mice"`: vowel_count = 2 (doesn't match), so keep → `"mice"` +| 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" | -**2.5 Join and Return:** +**2.4 Increment and Loop:** -```python -return ' '.join(res) # "cat dna mice" -``` +After processing all words, we join them with spaces. -**Time Complexity:** O(n) - Process each character once -**Space Complexity:** O(n) - Store words and result +**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. diff --git a/explanations/3776/en.md b/explanations/3776/en.md index 4c28839..03b4a90 100644 --- a/explanations/3776/en.md +++ b/explanations/3776/en.md @@ -2,99 +2,64 @@ ### Strategy (The "Why") -**Restate the problem:** We have a circular array where each person can transfer 1 unit to left or right neighbor. Find minimum moves to make all balances non-negative. Return -1 if impossible. +**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. **1.1 Constraints & Complexity:** -- **Input Size:** `1 <= n <= 10^5`, `-10^9 <= balance[i] <= 10^9` -- **Time Complexity:** O(n log n) - Sort positive indices by distance -- **Space Complexity:** O(n) - Store positive indices -- **Edge Case:** No negative balance (return 0), total sum < 0 (return -1) +- **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. **1.2 High-level approach:** -Find the negative balance index. Sort all positive indices by their circular distance from the negative index. Greedily transfer from closest positive neighbors until the negative is balanced. +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) **1.3 Brute force vs. optimized strategy:** -- **Brute Force:** Try all possible transfer sequences. This is exponential. -- **Optimized (Greedy):** Always transfer from the closest positive neighbor. This minimizes total moves. This is O(n log n) due to sorting. -- **Why it's better:** The greedy approach is optimal because transferring from closer neighbors minimizes the total distance traveled by units. +- **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. **1.4 Decomposition:** -1. Check if total sum < 0, return -1 -2. Find negative balance index -3. If no negative, return 0 -4. Sort positive indices by circular distance from negative -5. Greedily transfer from closest positives until negative is balanced -6. Return total moves +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). ### Steps (The "How") **2.1 Initialization & Example Setup:** -Let's use the example: `balance = [5,1,-4]` - -- Total sum: `5 + 1 - 4 = 2 >= 0` ✓ -- Negative index: `2` (value -4) - -**2.2 Check Total Sum:** - -```python -total = sum(balance) -if total < 0: - return -1 -``` - -**2.3 Find Negative Index:** - -```python -for i in range(n): - if balance[i] < 0: - neg_idx = i - break -``` +Let's use the example: `balance = [5, 1, -4]`, `n = 3`. -**2.4 Sort Positive Indices by Distance:** +- 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) -```python -positives = [] -for i in range(n): - if balance[i] > 0: - dist1 = (i - neg_idx) % n - dist2 = (neg_idx - i) % n - dist = min(dist1, dist2) - positives.append((dist, i, balance[i])) -positives.sort() -``` +**2.2 Start Processing:** -For `balance = [5,1,-4]`, `neg_idx = 2`: -- Index 0: dist = min(1, 2) = 1, amount = 5 -- Index 1: dist = min(2, 1) = 1, amount = 1 -- Sorted: `[(1, 0, 5), (1, 1, 1)]` +We calculate distances and sort positive balances. -**2.5 Greedily Transfer:** +**2.3 Trace Walkthrough:** -```python -needed = abs(balance[neg_idx]) # 4 -for dist, idx, amount in positives: - if needed <= 0: - break - transfer = min(needed, amount) - res += transfer * dist - needed -= transfer -``` +| 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) | -- From index 0: transfer 4, moves = 4 * 1 = 4 -- Needed = 0, done +We need 4 units total. We can take from index 0 (distance 1): transfer 4 units, cost = 4 * 1 = 4 moves. -**2.6 Return Result:** +**2.4 Increment and Loop:** -```python -return res if needed <= 0 else -1 # 4 -``` +After transferring from all necessary positive positions, we calculate the total moves. -**Time Complexity:** O(n log n) - Sort positive indices -**Space Complexity:** O(n) - Store positive indices +**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. diff --git a/explanations/3777/en.md b/explanations/3777/en.md index 0ec7f4d..6dc0238 100644 --- a/explanations/3777/en.md +++ b/explanations/3777/en.md @@ -2,74 +2,63 @@ ### Strategy (The "Why") -**Restate the problem:** We have a string of 'A' and 'B', and two types of queries: flip a character, or find minimum deletions to make a substring alternating. +**Restate the problem:** We have a binary string (only 'A' and 'B') and two types of queries: flip a character at index j, or compute the minimum deletions needed to make substring s[l..r] alternating (no two adjacent characters equal). **1.1 Constraints & Complexity:** -- **Input Size:** `1 <= n <= 10^5`, `1 <= q <= 10^5` -- **Time Complexity:** O(n + q log n) - Initialize Fenwick tree + q queries -- **Space Complexity:** O(n) - Fenwick tree -- **Edge Case:** Empty string, single character (always alternating) +- **Input Size:** String length n can be up to 10^5, and there can be up to 10^5 queries. +- **Time Complexity:** O(n + q log n) where n is string length and q is number of queries. Initialization is O(n), each flip is O(log n), and each query is O(log n) using Fenwick Tree. +- **Space Complexity:** O(n) for the Fenwick Tree and the converted array. +- **Edge Case:** If a substring is already alternating, no deletions are needed, so return 0. **1.2 High-level approach:** -Use a Fenwick Tree (Binary Indexed Tree) to track "violations" - adjacent identical characters. Each violation requires 1 deletion. For query type 2, count violations in the range. For query type 1, update violations at affected positions. +The goal is to efficiently track "violations" (adjacent identical characters) and support fast updates and range queries. We use a Fenwick Tree (Binary Indexed Tree) to count violations, where each violation represents one character that needs to be deleted. + +![Fenwick Tree for violations visualization](https://assets.leetcode.com/static_assets/others/fenwick-tree.png) **1.3 Brute force vs. optimized strategy:** -- **Brute Force:** For each type 2 query, scan the substring and count violations. This is O(q * n) time. -- **Optimized (Fenwick Tree):** Precompute violations, use Fenwick tree for range sum queries and point updates. This is O(n + q log n) time. -- **Why it's better:** Fenwick tree allows O(log n) range queries and updates, making it efficient for many queries. +- **Brute Force:** For each query, scan the substring to count violations, which would be O(n) per query, leading to O(q*n) total time. +- **Optimized Strategy:** Use a Fenwick Tree to store violation counts. Each flip updates at most 2 positions in O(log n) time, and each range query takes O(log n) time. Total: O(n + q log n). +- **Optimization:** The Fenwick Tree allows us to answer range sum queries (count violations in a range) and update single positions efficiently, making it ideal for this dynamic problem. **1.4 Decomposition:** -1. Convert string to 0-1 array (A=0, B=1) -2. Initialize Fenwick tree with violations (adjacent identical) +1. Convert the string to a 0-1 array (A=0, B=1). +2. Initialize Fenwick Tree: mark positions where adjacent characters are equal as violations. 3. For each query: - - Type 1: Flip character, update violations at i and i+1 - - Type 2: Query range sum of violations + - If type 1 (flip): update the character, then update violation status at positions i and i+1. + - If type 2 (query): return the count of violations in range [l, r] using range sum query. ### Steps (The "How") **2.1 Initialization & Example Setup:** -Let's use the example: `s = "ABA", queries = [[2,1,2],[1,1],[2,0,2]]` - -- Convert to array: `A = [0, 1, 0]` -- Initialize Fenwick tree - -**2.2 Initialize Violations:** - -```python -for i in range(n - 1): - if A[i] == A[i+1]: - bit.add(i + 1, 1) -``` +Let's use the example: `s = "ABA"`, `queries = [[2,1,2],[1,1],[2,0,2]]`. -For `"ABA"`: No violations initially (A≠B, B≠A) +- Convert to array: A = [0, 1, 0] +- Initialize Fenwick Tree: Check adjacent pairs + - A[0] == A[1]? 0 != 1, no violation + - A[1] == A[2]? 1 != 0, no violation +- Tree initially has no violations -**2.3 Process Queries:** +**2.2 Start Processing:** -**Query 1: [2, 1, 2]** - Query substring `s[1:3] = "BA"` -- Range sum: `bit.query(2) - bit.query(1) = 0 - 0 = 0` -- Result: `0` (already alternating) +We process each query sequentially. -**Query 2: [1, 1]** - Flip `s[1]` from B to A -- `A[1] ^= 1` → `A = [0, 0, 0]` -- Update violations: - - At position 0: `A[0] == A[1]` → add 1 - - At position 2: `A[1] == A[2]` → add 1 +**2.3 Trace Walkthrough:** -**Query 3: [2, 0, 2]** - Query substring `s[0:3] = "AAA"` -- Range sum: `bit.query(2) - bit.query(0) = 2 - 0 = 2` -- Result: `2` (need to delete 2 characters) +| Query | Type | Parameters | Before | Action | After | Violations in Range | Result | +|-------|------|------------|--------|--------|-------|---------------------|--------| +| 0 | 2 | [1,2] | "ABA" | Query range [1,2] | - | 0 | 0 | +| 1 | 1 | [1] | "ABA" | Flip s[1]: B→A | "AAA" | Update: A[1]==A[0]? Yes, add violation at 1. A[1]==A[2]? Yes, add violation at 2. | - | +| 2 | 2 | [0,2] | "AAA" | Query range [0,2] | - | 2 (positions 1 and 2) | 2 | -**2.4 Fenwick Tree Operations:** +**2.4 Increment and Loop:** -- `add(i, delta)`: Update tree at position i -- `query(i)`: Get prefix sum up to position i -- Range query `[l, r]`: `query(r) - query(l)` +After processing all queries, we return the results for type-2 queries. -**Time Complexity:** O(n + q log n) - Initialize + q queries -**Space Complexity:** O(n) - Fenwick tree +**2.5 Return Result:** +The result is `[0, 2]`. The first query finds 0 violations in "BA" (already alternating). After flipping, "AAA" has 2 violations, requiring 2 deletions to make it alternating (e.g., delete two 'A's to get "A"). diff --git a/solutions/3652/01.py b/solutions/3652/01.py new file mode 100644 index 0000000..2cb9783 --- /dev/null +++ b/solutions/3652/01.py @@ -0,0 +1,35 @@ +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] + + 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] + + # 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 + diff --git a/solutions/3769/01.py b/solutions/3769/01.py index 4e16664..a3a3a7c 100644 --- a/solutions/3769/01.py +++ b/solutions/3769/01.py @@ -1,9 +1,12 @@ class Solution: def sortByReflection(self, nums: List[int]) -> List[int]: def binary_reflection(n): - # Convert to binary, reverse, convert back + # Convert to binary, reverse, convert back to int binary = bin(n)[2:] # Remove '0b' prefix - reversed_binary = binary[::-1] - return int(reversed_binary, 2) + reversed_binary = binary[::-1] # Reverse the string + return int(reversed_binary, 2) # Convert back to int - return sorted(nums, key=lambda x: (binary_reflection(x), x)) + # 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/3774/01.py b/solutions/3774/01.py index 63399cb..060f7b7 100644 --- a/solutions/3774/01.py +++ b/solutions/3774/01.py @@ -1,7 +1,15 @@ class Solution: def absDifference(self, nums: List[int], k: int) -> int: - nums.sort() - sum_largest = sum(nums[-k:]) - sum_smallest = sum(nums[:k]) - return abs(sum_largest - sum_smallest) - + # Sort the array + sorted_nums = sorted(nums) + n = len(sorted_nums) + + # Sum of k largest elements (last k elements) + sum_largest = sum(sorted_nums[n - k:]) + + # Sum of k smallest elements (first k elements) + sum_smallest = sum(sorted_nums[:k]) + + # Return absolute difference + res = abs(sum_largest - sum_smallest) + return res diff --git a/solutions/3775/01.py b/solutions/3775/01.py index 85679cc..97c0dd2 100644 --- a/solutions/3775/01.py +++ b/solutions/3775/01.py @@ -1,19 +1,25 @@ 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 "" + return s - vowels = {'a', 'e', 'i', 'o', 'u'} - first_vowel_count = sum(1 for c in words[0] if c in vowels) + # Count vowels in first word + first_vowel_count = count_vowels(words[0]) + # Process remaining words res = [words[0]] - for word in words[1:]: - vowel_count = sum(1 for c in word if c in vowels) + for i in range(1, len(words)): + word = words[i] + vowel_count = count_vowels(word) if vowel_count == first_vowel_count: + # Reverse the word res.append(word[::-1]) else: res.append(word) return ' '.join(res) - diff --git a/solutions/3776/01.py b/solutions/3776/01.py index d67352e..ccf2eaa 100644 --- a/solutions/3776/01.py +++ b/solutions/3776/01.py @@ -7,45 +7,40 @@ def minMoves(self, balance: List[int]) -> int: if total < 0: return -1 - # Find the negative index - neg_idx = -1 + # Find the index with negative balance + neg_idx = None for i in range(n): if balance[i] < 0: neg_idx = i break - # If no negative, already balanced - if neg_idx == -1: + # If no negative balance, already balanced + if neg_idx is None: return 0 + # We need to transfer balance to neg_idx + # Greedily use nearest positive balances res = 0 - # Greedily transfer from nearest positive neighbors - # We need to move abs(balance[neg_idx]) units to neg_idx + neg_amount = abs(balance[neg_idx]) - needed = abs(balance[neg_idx]) - - # Try both directions and take minimum - # Actually, we need to find the optimal way to transfer - - # Sort positive indices by distance from negative index + # Create list of (distance, index, amount) for positive balances positives = [] for i in range(n): if balance[i] > 0: - # Calculate circular distance - dist1 = (i - neg_idx) % n - dist2 = (neg_idx - i) % n - dist = min(dist1, dist2) + # 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 use closest positives + # Greedily transfer from nearest positives + remaining = neg_amount for dist, idx, amount in positives: - if needed <= 0: + if remaining <= 0: break - transfer = min(needed, amount) + transfer = min(remaining, amount) res += transfer * dist - needed -= transfer + remaining -= transfer - return res if needed <= 0 else -1 - + return res diff --git a/solutions/3777/01.py b/solutions/3777/01.py index 685419c..382a9d6 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: @@ -17,29 +17,33 @@ def query(self, i): 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] - bit = FenwickTree(n) - # Initialize: mark violations (adjacent identical characters) + # Initialize Fenwick Tree + bit = FenwickTree(n) + # Mark violations (adjacent identical characters) for i in range(n - 1): - if A[i] == A[i+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 + A[i] ^= 1 # Flip the bit + # Update violations at position i and i+1 if i > 0: + # Check violation with left neighbor bit.add(i, 1 if A[i] == A[i - 1] else -1) if i < n - 1: + # Check violation with right neighbor bit.add(i + 1, 1 if A[i] == A[i + 1] else -1) else: - # Query operation [2, l, r] - # Count violations in range [l, r] + # 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 -