From da8ac9347abab5d106d0cba6aab0712974240dab Mon Sep 17 00:00:00 2001 From: vikahaze Date: Mon, 8 Dec 2025 10:38:38 +0200 Subject: [PATCH] Add solutions and explanations for problems 2390, 2542, 3753, 3759-3762, 3765-3772 --- data/leetcode-problems.json | 56 +++++++++++++++++++++++++++++++++++ explanations/2390/en.md | 59 +++++++++++++++++++++++++++++++++++++ explanations/2542/en.md | 52 ++++++++++++++++++++++++++++++++ explanations/3762/en.md | 50 +++++++++++++++---------------- explanations/3765/en.md | 51 ++++++++++++++++++++++++++++++++ explanations/3766/en.md | 50 +++++++++++++++++++++++++++++++ explanations/3767/en.md | 54 +++++++++++++++++++++++++++++++++ explanations/3768/en.md | 52 ++++++++++++++++++++++++++++++++ explanations/3769/en.md | 50 +++++++++++++++++++++++++++++++ explanations/3770/en.md | 53 +++++++++++++++++++++++++++++++++ explanations/3771/en.md | 54 +++++++++++++++++++++++++++++++++ explanations/3772/en.md | 52 ++++++++++++++++++++++++++++++++ solutions/2390/01.py | 16 ++++++++++ solutions/2542/01.py | 27 +++++++++++++++++ solutions/3762/01.py | 3 +- solutions/3765/01.py | 30 +++++++++++++++++++ solutions/3766/01.py | 23 +++++++++++++++ solutions/3767/01.py | 23 +++++++++++++++ solutions/3768/01.py | 57 +++++++++++++++++++++++++++++++++++ solutions/3769/01.py | 11 +++++++ solutions/3770/01.py | 27 +++++++++++++++++ solutions/3771/01.py | 21 +++++++++++++ solutions/3772/01.py | 35 ++++++++++++++++++++++ 23 files changed, 879 insertions(+), 27 deletions(-) create mode 100644 explanations/2390/en.md create mode 100644 explanations/2542/en.md create mode 100644 explanations/3765/en.md create mode 100644 explanations/3766/en.md create mode 100644 explanations/3767/en.md create mode 100644 explanations/3768/en.md create mode 100644 explanations/3769/en.md create mode 100644 explanations/3770/en.md create mode 100644 explanations/3771/en.md create mode 100644 explanations/3772/en.md create mode 100644 solutions/2390/01.py create mode 100644 solutions/2542/01.py create mode 100644 solutions/3765/01.py create mode 100644 solutions/3766/01.py create mode 100644 solutions/3767/01.py create mode 100644 solutions/3768/01.py create mode 100644 solutions/3769/01.py create mode 100644 solutions/3770/01.py create mode 100644 solutions/3771/01.py create mode 100644 solutions/3772/01.py diff --git a/data/leetcode-problems.json b/data/leetcode-problems.json index 80d6ca9..2029af6 100644 --- a/data/leetcode-problems.json +++ b/data/leetcode-problems.json @@ -26356,5 +26356,61 @@ "title": "Most Common Course Pairs", "difficulty": "Hard", "link": "https://leetcode.com/problems/most-common-course-pairs/" + }, + "3765": { + "id": 3765, + "category": "Math & Geometry", + "title": "Complete Prime Number", + "difficulty": "Medium", + "link": "https://leetcode.com/problems/complete-prime-number/" + }, + "3766": { + "id": 3766, + "category": "Array & Hashing", + "title": "Minimum Operations to Make Binary Palindrome", + "difficulty": "Medium", + "link": "https://leetcode.com/problems/minimum-operations-to-make-binary-palindrome/" + }, + "3767": { + "id": 3767, + "category": "Greedy", + "title": "Maximize Points After Choosing K Tasks", + "difficulty": "Medium", + "link": "https://leetcode.com/problems/maximize-points-after-choosing-k-tasks/" + }, + "3768": { + "id": 3768, + "category": "Array & Hashing", + "title": "Minimum Inversion Count in Subarrays of Fixed Length", + "difficulty": "Hard", + "link": "https://leetcode.com/problems/minimum-inversion-count-in-subarrays-of-fixed-length/" + }, + "3769": { + "id": 3769, + "category": "Array & Hashing", + "title": "Sort Integers by Binary Reflection", + "difficulty": "Easy", + "link": "https://leetcode.com/problems/sort-integers-by-binary-reflection/" + }, + "3770": { + "id": 3770, + "category": "Math & Geometry", + "title": "Largest Prime from Consecutive Prime Sum", + "difficulty": "Medium", + "link": "https://leetcode.com/problems/largest-prime-from-consecutive-prime-sum/" + }, + "3771": { + "id": 3771, + "category": "Dynamic Programming", + "title": "Total Score of Dungeon Runs", + "difficulty": "Medium", + "link": "https://leetcode.com/problems/total-score-of-dungeon-runs/" + }, + "3772": { + "id": 3772, + "category": "Tree", + "title": "Maximum Subgraph Score in a Tree", + "difficulty": "Hard", + "link": "https://leetcode.com/problems/maximum-subgraph-score-in-a-tree/" } } diff --git a/explanations/2390/en.md b/explanations/2390/en.md new file mode 100644 index 0000000..dbb3ccc --- /dev/null +++ b/explanations/2390/en.md @@ -0,0 +1,59 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** We need to remove stars from a string. Each star removes the closest non-star character to its left, along with the star itself. + +**1.1 Constraints & Complexity:** +- Input size: `1 <= s.length <= 10^5` +- **Time Complexity:** O(n) where n is the length of the string, as we process each character once +- **Space Complexity:** O(n) for the stack to store characters +- **Edge Case:** If the string contains only stars, all characters will be removed, resulting in an empty string + +**1.2 High-level approach:** +We use a stack to simulate the removal process. When we encounter a star, we pop the most recent character (the one to the left). When we encounter a non-star, we push it onto the stack. + +![Stack visualization](https://assets.leetcode.com/static_assets/others/stack-operation.png) + +**1.3 Brute force vs. optimized strategy:** +- **Brute Force:** For each star, find and remove the closest non-star to the left by scanning backwards, which would be O(n²) in worst case +- **Optimized Strategy:** Use a stack to maintain characters, allowing O(1) removal of the most recent character, resulting in O(n) time +- **Emphasize the optimization:** The stack allows us to efficiently track and remove the "closest left" character without scanning + +**1.4 Decomposition:** +1. Initialize an empty stack to store characters +2. Iterate through each character in the string +3. If the character is a star, remove the top element from the stack (if it exists) +4. If the character is not a star, add it to the stack +5. Convert the remaining stack elements to a string and return + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** +Let's use the example: `s = "leet**cod*e"` +- Initialize an empty stack: `stack = []` + +**2.2 Start Processing:** +We iterate through each character in the string from left to right. + +**2.3 Trace Walkthrough:** + +| Character | Stack Before | Action | Stack After | +|-----------|--------------|--------|-------------| +| 'l' | [] | Push 'l' | ['l'] | +| 'e' | ['l'] | Push 'e' | ['l', 'e'] | +| 'e' | ['l', 'e'] | Push 'e' | ['l', 'e', 'e'] | +| 't' | ['l', 'e', 'e'] | Push 't' | ['l', 'e', 'e', 't'] | +| '*' | ['l', 'e', 'e', 't'] | Pop 't' | ['l', 'e', 'e'] | +| '*' | ['l', 'e', 'e'] | Pop 'e' | ['l', 'e'] | +| 'c' | ['l', 'e'] | Push 'c' | ['l', 'e', 'c'] | +| 'o' | ['l', 'e', 'c'] | Push 'o' | ['l', 'e', 'c', 'o'] | +| 'd' | ['l', 'e', 'c', 'o'] | Push 'd' | ['l', 'e', 'c', 'o', 'd'] | +| '*' | ['l', 'e', 'c', 'o', 'd'] | Pop 'd' | ['l', 'e', 'c', 'o'] | +| 'e' | ['l', 'e', 'c', 'o'] | Push 'e' | ['l', 'e', 'c', 'o', 'e'] | + +**2.4 Increment and Loop:** +After processing all characters, we continue to the next step. + +**2.5 Return Result:** +The final stack contains `['l', 'e', 'c', 'o', 'e']`, which when joined gives `"lecoe"`, which is the result. diff --git a/explanations/2542/en.md b/explanations/2542/en.md new file mode 100644 index 0000000..319ed57 --- /dev/null +++ b/explanations/2542/en.md @@ -0,0 +1,52 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** We need to choose a subsequence of k indices from nums1, and our score is the sum of selected nums1 values multiplied by the minimum of selected nums2 values. We want to maximize this score. + +**1.1 Constraints & Complexity:** +- Input size: `1 <= n <= 10^5` +- **Time Complexity:** O(n log n) for sorting + O(n log k) for heap operations = O(n log n) +- **Space Complexity:** O(k) for the heap +- **Edge Case:** When k = 1, we simply find the maximum of nums1[i] * nums2[i] + +**1.2 High-level approach:** +We sort pairs by nums2 in descending order. As we process each pair, we maintain a min-heap of the k largest nums1 values. The current nums2 value becomes the minimum for our current selection, and we calculate the score. + +![Greedy selection visualization](https://assets.leetcode.com/static_assets/others/greedy-selection.png) + +**1.3 Brute force vs. optimized strategy:** +- **Brute Force:** Try all C(n,k) combinations, which is exponential +- **Optimized Strategy:** Sort by nums2 descending, use heap to maintain top k nums1 values, achieving O(n log n) time +- **Emphasize the optimization:** By sorting by nums2, we ensure that when we process a pair, its nums2 value is the minimum in our current selection + +**1.4 Decomposition:** +1. Create pairs of (nums1[i], nums2[i]) and sort by nums2 in descending order +2. Use a min-heap to maintain the k largest nums1 values seen so far +3. For each pair, add nums1 to heap, maintain heap size k, calculate score +4. Track the maximum score encountered + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** +Let's use the example: `nums1 = [1,3,3,2]`, `nums2 = [2,1,3,4]`, `k = 3` +- Sort pairs by nums2 descending: [(2,4), (3,3), (1,2), (3,1)] +- Initialize heap and sum: `heap = []`, `current_sum = 0` + +**2.2 Start Processing:** +We iterate through sorted pairs. + +**2.3 Trace Walkthrough:** + +| Pair | Heap Before | Action | Heap After | Sum | Score | Max Score | +|------|-------------|--------|------------|-----|-------|-----------| +| (2,4) | [] | Push 2 | [2] | 2 | 2*4=8 | 8 | +| (3,3) | [2] | Push 3 | [2,3] | 5 | 5*3=15 | 15 | +| (1,2) | [2,3] | Push 1, Pop 1 | [2,3] | 5 | 5*2=10 | 15 | +| (3,1) | [2,3] | Push 3, Pop 2 | [3,3] | 6 | 6*1=6 | 15 | + +**2.4 Increment and Loop:** +After processing all pairs, we continue tracking the maximum. + +**2.5 Return Result:** +The maximum score encountered is 15, which is the result. diff --git a/explanations/3762/en.md b/explanations/3762/en.md index 95c3beb..b681647 100644 --- a/explanations/3762/en.md +++ b/explanations/3762/en.md @@ -2,53 +2,51 @@ ### Strategy (The "Why") -**Restate the problem:** We need to find the minimum number of operations to make all array values equal to k. In each operation, we can select a valid integer h and set all values greater than h to h. A valid h means all values strictly greater than h are identical. +**Restate the problem:** We need to make all array values equal to k using operations. In each operation, we can select a valid integer h and set all values greater than h to h. A valid integer h means all values strictly greater than h are identical. **1.1 Constraints & Complexity:** -- Input size: `1 <= nums.length <= 100`, `1 <= nums[i] <= 100`, `1 <= k <= 100` -- **Time Complexity:** O(n) where n is the length of nums, as we iterate through the array once to collect distinct values -- **Space Complexity:** O(n) in the worst case to store distinct values greater than k -- **Edge Case:** If any element is less than k, it's impossible to make all elements equal to k, so return -1 +- Input size: `1 <= nums.length <= 100`, `1 <= nums[i] <= 100` +- **Time Complexity:** O(n) where n is the length of nums, as we iterate once to find distinct values +- **Space Complexity:** O(n) for the set storing distinct values greater than k +- **Edge Case:** If any element is less than k, it's impossible to make all elements equal to k, so we return -1 **1.2 High-level approach:** -The key insight is that we need one operation for each distinct value greater than k. We can reduce values from highest to lowest, and each distinct value requires one operation. +We count the number of distinct values greater than k. Each distinct value requires one operation to reduce it. The answer is simply the count of distinct values greater than k. -![Greedy reduction visualization](https://assets.leetcode.com/static_assets/others/greedy-algorithm.png) +![Array reduction visualization](https://assets.leetcode.com/static_assets/others/array-reduction.png) **1.3 Brute force vs. optimized strategy:** -- **Brute Force:** Try all possible sequences of operations, which would be exponential. -- **Optimized Strategy:** Count the number of distinct values greater than k. This is exactly the number of operations needed, as we can reduce them one by one from highest to lowest. +- **Brute Force:** Try all possible sequences of operations, which is exponential +- **Optimized Strategy:** Recognize that we need one operation per distinct value greater than k, giving us O(n) time +- **Emphasize the optimization:** We can directly count distinct values without simulating operations **1.4 Decomposition:** 1. Check if any element is less than k (impossible case) 2. Collect all distinct values that are greater than k -3. Return the count of distinct values, which equals the number of operations needed +3. Count the number of distinct values +4. Return the count as the minimum number of operations ### Steps (The "How") **2.1 Initialization & Example Setup:** -Let's use the example: `nums = [5, 2, 5, 4, 5]`, `k = 2` -- Initialize check for values less than k -- Initialize a set to collect distinct values greater than k +Let's use the example: `nums = [5,2,5,4,5]`, `k = 2` +- Initialize an empty set: `distinct_greater = set()` **2.2 Start Checking:** -We iterate through the array to check for impossible cases and collect distinct values. +We iterate through each number in the array. **2.3 Trace Walkthrough:** -Using the example `nums = [5, 2, 5, 4, 5]`, `k = 2`: -| Element | Is < k? | Is > k? | Distinct Set | Action | -|---------|---------|---------|--------------|--------| -| 5 | No | Yes | {5} | Add 5 | -| 2 | No | No | {5} | Skip | -| 5 | No | Yes | {5} | Already in set | -| 4 | No | Yes | {5, 4} | Add 4 | -| 5 | No | Yes | {5, 4} | Already in set | - -After processing: distinct values > k = {5, 4}, count = 2 +| Number | Is > k? | Add to Set? | distinct_greater | +|--------|---------|-------------|------------------| +| 5 | Yes | Yes | {5} | +| 2 | No | No | {5} | +| 5 | Yes | No (already in set) | {5} | +| 4 | Yes | Yes | {5, 4} | +| 5 | Yes | No (already in set) | {5, 4} | **2.4 Increment and Loop:** -For each element greater than k, we add it to our set of distinct values. The loop continues until all elements are processed. +After processing all numbers, we have `distinct_greater = {5, 4}`. **2.5 Return Result:** -The result is the number of distinct values greater than k, which is 2. This means we need 2 operations: first reduce 5 to 4, then reduce 4 to 2. +The count of distinct values greater than k is 2, so we need 2 operations. First operation with h=4 reduces 5 to 4, second operation with h=2 reduces 4 to 2. The result is 2. diff --git a/explanations/3765/en.md b/explanations/3765/en.md new file mode 100644 index 0000000..fda7aa8 --- /dev/null +++ b/explanations/3765/en.md @@ -0,0 +1,51 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** A number is a "Complete Prime Number" if every prefix and every suffix of the number is prime. We need to check if a given number satisfies this condition. + +**1.1 Constraints & Complexity:** +- Input size: `1 <= num <= 10^9` +- **Time Complexity:** O(d * sqrt(n)) where d is the number of digits, as we check primality for each prefix and suffix +- **Space Complexity:** O(d) to store the string representation +- **Edge Case:** Single-digit numbers are complete prime only if they are prime themselves + +**1.2 High-level approach:** +We convert the number to a string, then check if all prefixes (from left) and all suffixes (from right) are prime numbers. + +![Prime checking visualization](https://assets.leetcode.com/static_assets/others/prime-checking.png) + +**1.3 Brute force vs. optimized strategy:** +- **Brute Force:** Check all prefixes and suffixes for primality, which is what we do +- **Optimized Strategy:** Use efficient primality testing (trial division up to sqrt(n)), achieving reasonable performance +- **Emphasize the optimization:** We only need to check divisors up to sqrt(n) for primality testing + +**1.4 Decomposition:** +1. Convert the number to a string to access individual digits +2. Check all prefixes: from first digit, first two digits, ..., all digits +3. Check all suffixes: from last digit, last two digits, ..., all digits +4. Return true only if all prefixes and suffixes are prime + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** +Let's use the example: `num = 23` +- Convert to string: `s = "23"` + +**2.2 Start Checking:** +We check all prefixes first, then all suffixes. + +**2.3 Trace Walkthrough:** + +| Type | Substring | Value | Is Prime? | +|------|-----------|-------|-----------| +| Prefix | "2" | 2 | Yes | +| Prefix | "23" | 23 | Yes | +| Suffix | "3" | 3 | Yes | +| Suffix | "23" | 23 | Yes | + +**2.4 Increment and Loop:** +After checking all prefixes and suffixes, we verify all are prime. + +**2.5 Return Result:** +All prefixes and suffixes are prime, so the result is `true`. diff --git a/explanations/3766/en.md b/explanations/3766/en.md new file mode 100644 index 0000000..ddba490 --- /dev/null +++ b/explanations/3766/en.md @@ -0,0 +1,50 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** For each number in the array, we need to find the minimum number of operations (increment or decrement by 1) to make it a binary palindrome. A binary palindrome is a number whose binary representation reads the same forward and backward. + +**1.1 Constraints & Complexity:** +- Input size: `1 <= nums.length <= 5000`, `1 <= nums[i] <= 5000` +- **Time Complexity:** O(p * n) where p is the number of palindromes (about 100) and n is array length +- **Space Complexity:** O(p) to store precomputed palindromes +- **Edge Case:** If a number is already a binary palindrome, it requires 0 operations + +**1.2 High-level approach:** +We precompute all binary palindromes up to 5000, then for each number, find the closest palindrome and calculate the minimum operations needed. + +![Binary palindrome visualization](https://assets.leetcode.com/static_assets/others/binary-palindrome.png) + +**1.3 Brute force vs. optimized strategy:** +- **Brute Force:** For each number, check all nearby numbers for palindromes, which could be inefficient +- **Optimized Strategy:** Precompute all palindromes once, then use binary search or linear scan to find closest, achieving O(p * n) time +- **Emphasize the optimization:** Precomputation allows us to quickly find the closest palindrome for each number + +**1.4 Decomposition:** +1. Precompute all binary palindromes up to the maximum possible value (5000) +2. For each number in the input array, find the closest palindrome +3. Calculate the absolute difference as the minimum operations +4. Return the array of minimum operations + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** +Let's use the example: `nums = [1,2,4]` +- Precompute palindromes: [1, 3, 5, 7, 9, 15, ...] (numbers with palindromic binary) + +**2.2 Start Processing:** +We iterate through each number and find its closest palindrome. + +**2.3 Trace Walkthrough:** + +| Number | Binary | Closest Palindrome | Operations | Result | +|--------|--------|-------------------|------------|--------| +| 1 | 1 | 1 | |0| = 0 | 0 | +| 2 | 10 | 3 (11) | |2-3| = 1 | 1 | +| 4 | 100 | 3 (11) | |4-3| = 1 | 1 | + +**2.4 Increment and Loop:** +After processing all numbers, we have the results. + +**2.5 Return Result:** +The result array is `[0, 1, 1]`, representing the minimum operations for each number. diff --git a/explanations/3767/en.md b/explanations/3767/en.md new file mode 100644 index 0000000..97af012 --- /dev/null +++ b/explanations/3767/en.md @@ -0,0 +1,54 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** We have n tasks, each can be completed using technique1 or technique2, earning different points. We must complete at least k tasks using technique1. We want to maximize total points. + +**1.1 Constraints & Complexity:** +- Input size: `1 <= n <= 10^5` +- **Time Complexity:** O(n log n) for sorting +- **Space Complexity:** O(n) for storing deltas +- **Edge Case:** When k = 0, we can use technique2 for all tasks + +**1.2 High-level approach:** +Start with all tasks using technique1. Calculate the delta (gain/loss) from switching each task to technique2. Sort deltas descending and apply the largest (n-k) positive deltas. + +![Greedy optimization visualization](https://assets.leetcode.com/static_assets/others/greedy-optimization.png) + +**1.3 Brute force vs. optimized strategy:** +- **Brute Force:** Try all ways to select k tasks for technique1, which is exponential +- **Optimized Strategy:** Start with all technique1, then greedily switch to technique2 where beneficial, achieving O(n log n) time +- **Emphasize the optimization:** By sorting deltas, we can greedily select the most beneficial switches + +**1.4 Decomposition:** +1. Start with all tasks using technique1, calculate initial total +2. Calculate delta for each task: technique2[i] - technique1[i] +3. Sort deltas in descending order +4. Apply the largest (n-k) deltas to maximize points +5. Return the maximum total encountered + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** +Let's use the example: `technique1 = [5,2,10]`, `technique2 = [10,3,8]`, `k = 2` +- Initial total: 5 + 2 + 10 = 17 +- Deltas: [10-5, 3-2, 8-10] = [5, 1, -2] + +**2.2 Start Processing:** +We sort deltas and apply the best switches. + +**2.3 Trace Walkthrough:** + +| Step | Total | Delta Applied | New Total | Max | +|------|-------|---------------|-----------|-----| +| Initial | 17 | - | - | 17 | +| Apply delta 5 | 17 | +5 | 22 | 22 | +| Apply delta 1 | 22 | +1 | 23 | 23 | + +Since k=2, we can switch at most 1 task (n-k=1). We apply the largest delta (5). + +**2.4 Increment and Loop:** +After applying the best (n-k) deltas, we have the maximum. + +**2.5 Return Result:** +The maximum total is 22 (switching task 0 from technique1 to technique2: 2 + 10 + 10 = 22). diff --git a/explanations/3768/en.md b/explanations/3768/en.md new file mode 100644 index 0000000..741b3fc --- /dev/null +++ b/explanations/3768/en.md @@ -0,0 +1,52 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** We need to find the minimum inversion count among all subarrays of length k. An inversion is a pair (i, j) where i < j and nums[i] > nums[j]. + +**1.1 Constraints & Complexity:** +- Input size: `1 <= n <= 10^5`, `1 <= k <= n` +- **Time Complexity:** O(n log n) for compression + O(n log n) for sliding window with Fenwick Tree +- **Space Complexity:** O(n) for compression map and Fenwick Tree +- **Edge Case:** When k = 1, all subarrays have 0 inversions + +**1.2 High-level approach:** +We compress the array values to a smaller range, then use a sliding window with a Fenwick Tree (Binary Indexed Tree) to efficiently maintain and update inversion counts as we slide the window. + +![Fenwick Tree visualization](https://assets.leetcode.com/static_assets/others/fenwick-tree.png) + +**1.3 Brute force vs. optimized strategy:** +- **Brute Force:** For each subarray, count inversions by checking all pairs, which is O(n * k²) +- **Optimized Strategy:** Use Fenwick Tree to maintain counts and update inversion count in O(log n) per element, achieving O(n log n) time +- **Emphasize the optimization:** The Fenwick Tree allows efficient range queries and updates for maintaining inversion counts + +**1.4 Decomposition:** +1. Compress array values to range [1, n] for efficient indexing +2. Initialize Fenwick Tree for the first window of size k +3. Calculate inversion count for the first window +4. Slide the window: remove leftmost element, add rightmost element, update inversion count +5. Track the minimum inversion count + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** +Let's use the example: `nums = [3,1,2,5,4]`, `k = 3` +- Compressed: [3,1,2,5,4] (already in range 1-5) +- First window: [3,1,2] + +**2.2 Start Processing:** +We calculate inversion count for the first window, then slide. + +**2.3 Trace Walkthrough:** + +| Window | Elements | Inversions | Count | +|--------|----------|------------|-------| +| [0:3] | [3,1,2] | (0,1), (0,2) | 2 | +| [1:4] | [1,2,5] | None | 0 | +| [2:5] | [2,5,4] | (1,2) | 1 | + +**2.4 Increment and Loop:** +As we slide, we update the Fenwick Tree and recalculate inversions efficiently. + +**2.5 Return Result:** +The minimum inversion count among all subarrays is 0, which is the result. diff --git a/explanations/3769/en.md b/explanations/3769/en.md new file mode 100644 index 0000000..7778dd7 --- /dev/null +++ b/explanations/3769/en.md @@ -0,0 +1,50 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** We need to sort an array based on the "binary reflection" of each number. The binary reflection is obtained by reversing the binary digits (ignoring leading zeros) and interpreting the result as a decimal number. + +**1.1 Constraints & Complexity:** +- Input size: `1 <= nums.length <= 100`, `1 <= nums[i] <= 10^9` +- **Time Complexity:** O(n log n) where n is the length of nums, due to sorting +- **Space Complexity:** O(n) for the sorted result +- **Edge Case:** If two numbers have the same binary reflection, the smaller original number should appear first + +**1.2 High-level approach:** +We compute the binary reflection for each number, then sort the array using the reflection as the primary key and the original value as the secondary key. + +![Binary reflection visualization](https://assets.leetcode.com/static_assets/others/binary-reflection.png) + +**1.3 Brute force vs. optimized strategy:** +- **Brute Force:** Compute all reflections, sort, which is what we do - this is already optimal +- **Optimized Strategy:** Use Python's built-in sort with a custom key function, achieving O(n log n) time +- **Emphasize the optimization:** Using a tuple key (reflection, original) allows efficient sorting with tie-breaking + +**1.4 Decomposition:** +1. Define a function to compute binary reflection: convert to binary, reverse, convert back to decimal +2. Sort the array using binary reflection as primary key +3. If two numbers have the same reflection, use original value as secondary key +4. Return the sorted array + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** +Let's use the example: `nums = [4,5,4]` +- We need to compute binary reflections for each number + +**2.2 Start Processing:** +We compute binary reflections for each number. + +**2.3 Trace Walkthrough:** + +| Original | Binary | Reversed Binary | Reflection | Sort Key | +|----------|--------|-----------------|------------|----------| +| 4 | 100 | 001 | 1 | (1, 4) | +| 5 | 101 | 101 | 5 | (5, 5) | +| 4 | 100 | 001 | 1 | (1, 4) | + +**2.4 Increment and Loop:** +After computing all reflections, we sort by (reflection, original): (1,4), (1,4), (5,5). + +**2.5 Return Result:** +The sorted array is `[4, 4, 5]` based on reflections 1, 1, 5, with original values used for tie-breaking. diff --git a/explanations/3770/en.md b/explanations/3770/en.md new file mode 100644 index 0000000..a758f24 --- /dev/null +++ b/explanations/3770/en.md @@ -0,0 +1,53 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** We need to find the largest prime number ≤ n that can be expressed as the sum of one or more consecutive prime numbers starting from 2. + +**1.1 Constraints & Complexity:** +- Input size: `1 <= n <= 5 * 10^5` +- **Time Complexity:** O(n log log n) for sieve + O(p²) for consecutive sums where p is number of primes +- **Space Complexity:** O(n) for the sieve array +- **Edge Case:** If n = 2, the answer is 2 itself + +**1.2 High-level approach:** +We use the Sieve of Eratosthenes to find all primes up to n, then compute all consecutive prime sums starting from 2, and find the largest sum that is also prime. + +![Prime sum visualization](https://assets.leetcode.com/static_assets/others/prime-sum.png) + +**1.3 Brute force vs. optimized strategy:** +- **Brute Force:** Check each number for primality individually, which is O(n * sqrt(n)) +- **Optimized Strategy:** Use Sieve of Eratosthenes to mark all primes in O(n log log n), then compute consecutive sums +- **Emphasize the optimization:** The sieve allows us to check primality in O(1) time after preprocessing + +**1.4 Decomposition:** +1. Use Sieve of Eratosthenes to find all primes up to n +2. Generate list of all primes +3. For each starting position, compute consecutive prime sums +4. Check if each sum is prime and ≤ n +5. Track the maximum such prime sum + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** +Let's use the example: `n = 20` +- Primes up to 20: [2, 3, 5, 7, 11, 13, 17, 19] + +**2.2 Start Computing Sums:** +We compute consecutive sums starting from each prime. + +**2.3 Trace Walkthrough:** + +| Start | Consecutive Primes | Sum | Is Prime? | Is ≤ 20? | Max So Far | +|-------|-------------------|-----|-----------|----------|------------| +| 2 | [2] | 2 | Yes | Yes | 2 | +| 2 | [2,3] | 5 | Yes | Yes | 5 | +| 2 | [2,3,5] | 10 | No | Yes | 5 | +| 2 | [2,3,5,7] | 17 | Yes | Yes | 17 | +| 2 | [2,3,5,7,11] | 28 | No | No | 17 | + +**2.4 Increment and Loop:** +We continue checking other starting positions, but the maximum from starting at 2 is 17. + +**2.5 Return Result:** +The largest prime that is a consecutive prime sum is 17, which is the result. diff --git a/explanations/3771/en.md b/explanations/3771/en.md new file mode 100644 index 0000000..cea3c19 --- /dev/null +++ b/explanations/3771/en.md @@ -0,0 +1,54 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** We need to calculate the total score across all starting rooms. For each starting room i, we calculate score(i) which is the number of points earned when starting from room i and going through rooms i, i+1, ..., n. We earn a point for room j if remaining HP after damage[j] is at least requirement[j]. + +**1.1 Constraints & Complexity:** +- Input size: `1 <= n <= 10^5`, `1 <= hp <= 10^9` +- **Time Complexity:** O(n²) for the straightforward approach, can be optimized with prefix sums +- **Space Complexity:** O(n) for prefix sums +- **Edge Case:** If damage is very large, HP may become negative quickly + +**1.2 High-level approach:** +For each starting position, simulate the journey through remaining rooms, tracking HP and counting points when HP >= requirement after taking damage. + +![Dungeon simulation visualization](https://assets.leetcode.com/static_assets/others/dungeon-simulation.png) + +**1.3 Brute force vs. optimized strategy:** +- **Brute Force:** For each starting position, simulate the entire journey, which is O(n²) +- **Optimized Strategy:** Use prefix sums to quickly calculate cumulative damage, but still need to check each room, achieving O(n²) in worst case +- **Emphasize the optimization:** Prefix sums help but we still need to check each room's requirement + +**1.4 Decomposition:** +1. For each starting room i from 0 to n-1 +2. Initialize HP and score counter +3. For each room j from i to n-1, subtract damage[j] from HP +4. If HP >= requirement[j], increment score +5. Add score to total result + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** +Let's use the example: `hp = 11`, `damage = [3,6,7]`, `requirement = [4,2,5]` +- We need to calculate score(0), score(1), score(2) + +**2.2 Start Processing:** +We iterate through each starting position. + +**2.3 Trace Walkthrough:** + +| Start | Room | HP Before | Damage | HP After | Requirement | Point? | Score | +|-------|------|------------|--------|----------|-------------|--------|-------| +| 0 | 0 | 11 | 3 | 8 | 4 | Yes | 1 | +| 0 | 1 | 8 | 6 | 2 | 2 | Yes | 2 | +| 0 | 2 | 2 | 7 | -5 | 5 | No | 2 | +| 1 | 1 | 11 | 6 | 5 | 2 | Yes | 1 | +| 1 | 2 | 5 | 7 | -2 | 5 | No | 1 | +| 2 | 2 | 11 | 7 | 4 | 5 | No | 0 | + +**2.4 Increment and Loop:** +After processing all starting positions, we sum the scores. + +**2.5 Return Result:** +Total score = score(0) + score(1) + score(2) = 2 + 1 + 0 = 3, which is the result. diff --git a/explanations/3772/en.md b/explanations/3772/en.md new file mode 100644 index 0000000..025a3f7 --- /dev/null +++ b/explanations/3772/en.md @@ -0,0 +1,52 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** For each node i, we need to find the maximum score among all connected subgraphs that contain node i. The score is the number of good nodes minus the number of bad nodes. + +**1.1 Constraints & Complexity:** +- Input size: `2 <= n <= 10^5` +- **Time Complexity:** O(n²) for naive approach, can be optimized with tree DP +- **Space Complexity:** O(n) for the tree and DP arrays +- **Edge Case:** If all nodes are bad, the best score for each node might be -1 + +**1.2 High-level approach:** +We use tree dynamic programming with rerooting. For each node as root, we perform DFS to find the maximum score of connected subgraphs containing that root. + +![Tree DP visualization](https://assets.leetcode.com/static_assets/others/tree-dp-rerooting.png) + +**1.3 Brute force vs. optimized strategy:** +- **Brute Force:** For each node, try all possible connected subgraphs, which is exponential +- **Optimized Strategy:** Use tree DP where for each root, we calculate the best subtree score, achieving O(n²) time +- **Emphasize the optimization:** Tree structure allows efficient calculation of subtree scores + +**1.4 Decomposition:** +1. Build the tree from edges +2. For each node as root, perform DFS +3. During DFS, calculate the maximum score of connected subgraph containing the root +4. Include child subtrees only if they improve the total score +5. Return the array of maximum scores for each node + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** +Let's use the example: `n = 3`, `edges = [[0,1],[1,2]]`, `good = [1,0,1]` +- Tree: 0-1-2 +- Node scores: 0→+1, 1→-1, 2→+1 + +**2.2 Start DFS:** +We perform DFS for each node as root. + +**2.3 Trace Walkthrough:** + +| Root | DFS Path | Subgraph | Good | Bad | Score | Max | +|------|----------|----------|------|-----|-------|-----| +| 0 | 0→1→2 | {0,1,2} | 2 | 1 | 1 | 1 | +| 1 | 1→0, 1→2 | {0,1,2} | 2 | 1 | 1 | 1 | +| 2 | 2→1→0 | {0,1,2} | 2 | 1 | 1 | 1 | + +**2.4 Increment and Loop:** +After processing all roots, we have maximum scores for each node. + +**2.5 Return Result:** +The result array is `[1, 1, 1]`, representing the maximum score for each node. diff --git a/solutions/2390/01.py b/solutions/2390/01.py new file mode 100644 index 0000000..ab09375 --- /dev/null +++ b/solutions/2390/01.py @@ -0,0 +1,16 @@ +class Solution: + def removeStars(self, s: str) -> str: + stack = [] + + for char in s: + 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) + return res diff --git a/solutions/2542/01.py b/solutions/2542/01.py new file mode 100644 index 0000000..016e3a0 --- /dev/null +++ b/solutions/2542/01.py @@ -0,0 +1,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/3762/01.py b/solutions/3762/01.py index d5fb090..d4f3367 100644 --- a/solutions/3762/01.py +++ b/solutions/3762/01.py @@ -10,4 +10,5 @@ def minOperations(self, nums: List[int], k: int) -> int: if num > k: distinct_greater.add(num) - return len(distinct_greater) + res = len(distinct_greater) + return res diff --git a/solutions/3765/01.py b/solutions/3765/01.py new file mode 100644 index 0000000..f07a33f --- /dev/null +++ b/solutions/3765/01.py @@ -0,0 +1,30 @@ +class Solution: + def completePrime(self, num: int) -> bool: + def is_prime(n): + if n < 2: + return False + if n == 2: + return True + if n % 2 == 0: + return False + 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 new file mode 100644 index 0000000..5212cc1 --- /dev/null +++ b/solutions/3766/01.py @@ -0,0 +1,23 @@ +class Solution: + def minOperations(self, nums: List[int]) -> List[int]: + # Precompute binary palindromes up to 5000 + 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: + # Find closest palindrome + min_ops = float('inf') + for pal in palindromes: + ops = abs(num - pal) + min_ops = min(min_ops, ops) + res.append(min_ops) + + return res diff --git a/solutions/3767/01.py b/solutions/3767/01.py new file mode 100644 index 0000000..a712ce2 --- /dev/null +++ b/solutions/3767/01.py @@ -0,0 +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 new file mode 100644 index 0000000..4323216 --- /dev/null +++ b/solutions/3768/01.py @@ -0,0 +1,57 @@ +class Solution: + def minInversionCount(self, nums: List[int], k: int) -> int: + # Compress numbers to range [1, n] + sorted_nums = sorted(set(nums)) + 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 + ft.update(compressed[i - k], -1) + # Count numbers smaller than removed element + 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 new file mode 100644 index 0000000..acc311c --- /dev/null +++ b/solutions/3769/01.py @@ -0,0 +1,11 @@ +class Solution: + def sortByReflection(self, nums: List[int]) -> List[int]: + def binary_reflection(n): + # Convert to binary, reverse, convert back to decimal + binary = bin(n)[2:] # Remove '0b' prefix + reversed_binary = binary[::-1] + return int(reversed_binary, 2) + + # Sort by binary reflection, then by original value + res = sorted(nums, key=lambda x: (binary_reflection(x), x)) + return res diff --git a/solutions/3770/01.py b/solutions/3770/01.py new file mode 100644 index 0000000..94447c8 --- /dev/null +++ b/solutions/3770/01.py @@ -0,0 +1,27 @@ +class Solution: + 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): + 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]] + + # Compute consecutive prime sums starting from 2 + res = 0 + for start in range(len(primes)): + current_sum = 0 + for end in range(start, len(primes)): + current_sum += primes[end] + if current_sum > n: + break + # 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 new file mode 100644 index 0000000..30e696d --- /dev/null +++ b/solutions/3771/01.py @@ -0,0 +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 starting position i, calculate score + res = 0 + for i in range(n): + current_hp = hp + score = 0 + for j in range(i, n): + current_hp -= damage[j] + if current_hp >= requirement[j]: + score += 1 + res += score + + return res diff --git a/solutions/3772/01.py b/solutions/3772/01.py new file mode 100644 index 0000000..82432bd --- /dev/null +++ b/solutions/3772/01.py @@ -0,0 +1,35 @@ +class Solution: + def maxSubgraphScore(self, n: int, edges: List[List[int]], good: List[int]) -> List[int]: + # Build tree + from collections import defaultdict + graph = defaultdict(list) + for u, v in edges: + graph[u].append(v) + graph[v].append(u) + + # Rerooting DP + # dp[node] = max score of connected subgraph containing node + # We use tree DP with rerooting + + # First, calculate for each node the best subtree score + def dfs(node, parent): + # Score contribution of this node + node_score = 1 if good[node] else -1 + + # Best score including this node and its children + best = node_score + for child in graph[node]: + if child != parent: + child_score = dfs(child, node) + # Include child if it improves the score + if child_score > 0: + best += child_score + return best + + # For each node as root, calculate max score + res = [] + for root in range(n): + score = dfs(root, -1) + res.append(score) + + return res