From 6bbd7e389122ef38851d72c95347c6468d0b86a3 Mon Sep 17 00:00:00 2001 From: vikahaze Date: Tue, 9 Dec 2025 06:53:47 +0200 Subject: [PATCH 1/2] Add solutions and explanations for problems 3583, 3772, 3771, 3770, 3766, 3768, 3767, 3765, 3761, 3760 --- books/All.md | 62 ++++++++++++++++++++++++++++++++++++++ books/LeetCode_75.md | 62 ++++++++++++++++++++++++++++++++++++++ books/Visualization.md | 62 ++++++++++++++++++++++++++++++++++++++ data/book-sets.json | 28 ++++++++--------- explanations/3583/en.md | 56 ++++++++++++++++++++++++++++++++++ explanations/3760/en.md | 57 ++++++++++++++++------------------- explanations/3761/en.md | 67 +++++++++++++++++++---------------------- explanations/3771/en.md | 40 ++++++++++++------------ explanations/3772/en.md | 48 +++++++++++++++++------------ solutions/3583/01.py | 42 ++++++++++++++++++++++++++ solutions/3760/01.py | 64 ++++----------------------------------- solutions/3761/01.py | 57 +++++++++-------------------------- solutions/3766/01.py | 15 ++++++--- solutions/3770/01.py | 23 ++++++++------ solutions/3771/01.py | 23 ++++++++------ solutions/3772/01.py | 63 +++++++++++++++++++++++--------------- 16 files changed, 500 insertions(+), 269 deletions(-) create mode 100644 explanations/3583/en.md create mode 100644 solutions/3583/01.py diff --git a/books/All.md b/books/All.md index f59526f..6104f46 100644 --- a/books/All.md +++ b/books/All.md @@ -8922,6 +8922,68 @@ class Solution: return res ``` +## 1431. Kids With the Greatest Number of Candies [Easy] +https://leetcode.com/problems/kids-with-the-greatest-number-of-candies/ + +### Explanation + +## 1431. Kids With the Greatest Number of Candies [Easy] + +https://leetcode.com/problems/kids-with-the-greatest-number-of-candies + +## Description +There are `n` kids with candies. You are given an integer array `candies`, where each `candies[i]` represents the number of candies the `i`th kid has, and an integer `extraCandies`, denoting the number of extra candies that you have. + +Return a boolean array `result` of length `n`, where `result[i]` is `true` if, after giving the `i`th kid all the `extraCandies`, they will have the greatest number of candies among all the kids, or false otherwise. + +Note that multiple kids can have the greatest number of candies. + +**Examples** + +```text +Input: candies = [2,3,5,1,3], extraCandies = 3 +Output: [true,true,true,false,true] +Explanation: If you give all extraCandies to: +- Kid 1, they will have 2 + 3 = 5 candies, which is the greatest among the kids. +- Kid 2, they will have 3 + 3 = 6 candies, which is the greatest among the kids. +- Kid 3, they will have 5 + 3 = 8 candies, which is the greatest among the kids. +- Kid 4, they will have 1 + 3 = 4 candies, which is not the greatest among the kids. +- Kid 5, they will have 3 + 3 = 6 candies, which is the greatest among the kids. + +Input: candies = [4,2,1,1,2], extraCandies = 1 +Output: [true,false,false,false,false] + +Input: candies = [12,1,12], extraCandies = 10 +Output: [true,false,true] +``` + +**Constraints** + +```text +- n == candies.length +- 2 <= n <= 100 +- 1 <= candies[i] <= 100 +- 1 <= extraCandies <= 50 +``` + +## Hint +For each kid, check if their candies plus `extraCandies` is at least as much as the current maximum. + +## Explanation +First, you want to know the highest number of candies any kid currently has. This is important because you need a reference point to see if giving extra candies to a kid will make them "the greatest." + +For each kid, you add the `extraCandies` to their current amount. You do this because you want to see if, after the bonus, they can reach or beat the current maximum. If they do, you mark them as `True` in our answer list; otherwise, False. + +You only need to find the maximum once, and then just compare each kid's total to it. Don't need to recalculate the maximum for every kid. + +### Solution + +```python +def kidsWithCandies(candies, extraCandies): + max_candies = max(candies) # Find the current maximum + return [(c + extraCandies) >= max_candies for c in candies] +``` + ## 1448. Count Good Nodes in Binary Tree [Medium] https://leetcode.com/problems/count-good-nodes-in-binary-tree/ diff --git a/books/LeetCode_75.md b/books/LeetCode_75.md index 1644d29..855013e 100644 --- a/books/LeetCode_75.md +++ b/books/LeetCode_75.md @@ -517,6 +517,68 @@ def uniqueOccurrences(arr): return len(set(count.values())) == len(count) ``` +## 1431. Kids With the Greatest Number of Candies [Easy] +https://leetcode.com/problems/kids-with-the-greatest-number-of-candies/ + +### Explanation + +## 1431. Kids With the Greatest Number of Candies [Easy] + +https://leetcode.com/problems/kids-with-the-greatest-number-of-candies + +## Description +There are `n` kids with candies. You are given an integer array `candies`, where each `candies[i]` represents the number of candies the `i`th kid has, and an integer `extraCandies`, denoting the number of extra candies that you have. + +Return a boolean array `result` of length `n`, where `result[i]` is `true` if, after giving the `i`th kid all the `extraCandies`, they will have the greatest number of candies among all the kids, or false otherwise. + +Note that multiple kids can have the greatest number of candies. + +**Examples** + +```text +Input: candies = [2,3,5,1,3], extraCandies = 3 +Output: [true,true,true,false,true] +Explanation: If you give all extraCandies to: +- Kid 1, they will have 2 + 3 = 5 candies, which is the greatest among the kids. +- Kid 2, they will have 3 + 3 = 6 candies, which is the greatest among the kids. +- Kid 3, they will have 5 + 3 = 8 candies, which is the greatest among the kids. +- Kid 4, they will have 1 + 3 = 4 candies, which is not the greatest among the kids. +- Kid 5, they will have 3 + 3 = 6 candies, which is the greatest among the kids. + +Input: candies = [4,2,1,1,2], extraCandies = 1 +Output: [true,false,false,false,false] + +Input: candies = [12,1,12], extraCandies = 10 +Output: [true,false,true] +``` + +**Constraints** + +```text +- n == candies.length +- 2 <= n <= 100 +- 1 <= candies[i] <= 100 +- 1 <= extraCandies <= 50 +``` + +## Hint +For each kid, check if their candies plus `extraCandies` is at least as much as the current maximum. + +## Explanation +First, you want to know the highest number of candies any kid currently has. This is important because you need a reference point to see if giving extra candies to a kid will make them "the greatest." + +For each kid, you add the `extraCandies` to their current amount. You do this because you want to see if, after the bonus, they can reach or beat the current maximum. If they do, you mark them as `True` in our answer list; otherwise, False. + +You only need to find the maximum once, and then just compare each kid's total to it. Don't need to recalculate the maximum for every kid. + +### Solution + +```python +def kidsWithCandies(candies, extraCandies): + max_candies = max(candies) # Find the current maximum + return [(c + extraCandies) >= max_candies for c in candies] +``` + ## 2215. Find the Difference of Two Arrays [Easy] https://leetcode.com/problems/find-the-difference-of-two-arrays/ diff --git a/books/Visualization.md b/books/Visualization.md index d8300b2..f58ae53 100644 --- a/books/Visualization.md +++ b/books/Visualization.md @@ -86,6 +86,68 @@ def __init__(self, val=0, next=None): self.next = next ``` +## 1431. Kids With the Greatest Number of Candies [Easy] +https://leetcode.com/problems/kids-with-the-greatest-number-of-candies/ + +### Explanation + +## 1431. Kids With the Greatest Number of Candies [Easy] + +https://leetcode.com/problems/kids-with-the-greatest-number-of-candies + +## Description +There are `n` kids with candies. You are given an integer array `candies`, where each `candies[i]` represents the number of candies the `i`th kid has, and an integer `extraCandies`, denoting the number of extra candies that you have. + +Return a boolean array `result` of length `n`, where `result[i]` is `true` if, after giving the `i`th kid all the `extraCandies`, they will have the greatest number of candies among all the kids, or false otherwise. + +Note that multiple kids can have the greatest number of candies. + +**Examples** + +```text +Input: candies = [2,3,5,1,3], extraCandies = 3 +Output: [true,true,true,false,true] +Explanation: If you give all extraCandies to: +- Kid 1, they will have 2 + 3 = 5 candies, which is the greatest among the kids. +- Kid 2, they will have 3 + 3 = 6 candies, which is the greatest among the kids. +- Kid 3, they will have 5 + 3 = 8 candies, which is the greatest among the kids. +- Kid 4, they will have 1 + 3 = 4 candies, which is not the greatest among the kids. +- Kid 5, they will have 3 + 3 = 6 candies, which is the greatest among the kids. + +Input: candies = [4,2,1,1,2], extraCandies = 1 +Output: [true,false,false,false,false] + +Input: candies = [12,1,12], extraCandies = 10 +Output: [true,false,true] +``` + +**Constraints** + +```text +- n == candies.length +- 2 <= n <= 100 +- 1 <= candies[i] <= 100 +- 1 <= extraCandies <= 50 +``` + +## Hint +For each kid, check if their candies plus `extraCandies` is at least as much as the current maximum. + +## Explanation +First, you want to know the highest number of candies any kid currently has. This is important because you need a reference point to see if giving extra candies to a kid will make them "the greatest." + +For each kid, you add the `extraCandies` to their current amount. You do this because you want to see if, after the bonus, they can reach or beat the current maximum. If they do, you mark them as `True` in our answer list; otherwise, False. + +You only need to find the maximum once, and then just compare each kid's total to it. Don't need to recalculate the maximum for every kid. + +### Solution + +```python +def kidsWithCandies(candies, extraCandies): + max_candies = max(candies) # Find the current maximum + return [(c + extraCandies) >= max_candies for c in candies] +``` + ## 1798. Maximum Number of Consecutive Values You Can Make [Medium] https://leetcode.com/problems/maximum-number-of-consecutive-values-you-can-make/ diff --git a/data/book-sets.json b/data/book-sets.json index 45e4fbd..63672d9 100644 --- a/data/book-sets.json +++ b/data/book-sets.json @@ -57,13 +57,13 @@ 202, 205, 206, 207, 208, 209, 210, 211, 212, 215, 216, 217, 219, 221, 222, 224, 226, 228, 230, 234, 235, 236, 238, 240, 242, 268, 274, 278, 283, 287, 289, 290, 295, 297, 300, 322, 328, 334, 337, 338, 344, 345, 347, 373, 374, 378, 380, 383, 392, 394, 399, 409, 412, 427, 433, 435, 437, 438, 443, 448, 450, 452, 460, 494, 502, 509, 530, 543, 547, 560, 581, 605, 617, 637, 643, 647, 649, 695, 700, 701, 704, 714, 724, 733, 735, 739, 746, - 790, 841, 872, 875, 876, 901, 909, 918, 933, 973, 981, 994, 997, 1004, 1029, 1046, 1127, 1137, 1143, 1161, 1167, 1207, 1249, 1268, 1288, 1304, - 1318, 1337, 1372, 1423, 1448, 1456, 1466, 1480, 1493, 1515, 1523, 1528, 1557, 1584, 1657, 1672, 1679, 1704, 1732, 1798, 1920, 1925, 1926, 1929, - 1957, 1963, 2011, 2095, 2119, 2130, 2211, 2215, 2300, 2336, 2352, 2390, 2419, 2462, 2542, 2627, 2703, 2723, 2769, 2807, 2862, 2879, 2884, 2888, - 2894, 2942, 3100, 3110, 3133, 3164, 3190, 3197, 3228, 3291, 3320, 3351, 3380, 3381, 3413, 3424, 3432, 3444, 3471, 3512, 3522, 3602, 3603, 3606, - 3607, 3608, 3622, 3623, 3625, 3663, 3668, 3678, 3683, 3688, 3692, 3697, 3701, 3707, 3712, 3718, 3722, 3723, 3724, 3726, 3727, 3728, 3731, 3736, - 3737, 3738, 3739, 3740, 3741, 3742, 3743, 3745, 3747, 3748, 3750, 3751, 3752, 3753, 3754, 3755, 3756, 3757, 3759, 3760, 3761, 3762, 3764, 3765, - 3766, 3767, 3768, 3769, 3770, 3771, 3772 + 790, 841, 872, 875, 876, 901, 909, 918, 933, 973, 981, 994, 997, 1004, 1029, 1046, 1071, 1127, 1137, 1143, 1161, 1167, 1207, 1249, 1268, 1288, + 1304, 1318, 1337, 1372, 1423, 1431, 1448, 1456, 1466, 1480, 1493, 1515, 1523, 1528, 1557, 1584, 1657, 1672, 1679, 1704, 1732, 1768, 1798, 1920, + 1925, 1926, 1929, 1957, 1963, 2011, 2095, 2119, 2130, 2211, 2215, 2300, 2336, 2352, 2390, 2419, 2462, 2542, 2627, 2703, 2723, 2769, 2807, 2862, + 2879, 2884, 2888, 2894, 2942, 3100, 3110, 3133, 3164, 3190, 3197, 3228, 3291, 3320, 3351, 3380, 3381, 3413, 3424, 3432, 3444, 3471, 3512, 3522, + 3583, 3602, 3603, 3606, 3607, 3608, 3622, 3623, 3625, 3663, 3668, 3678, 3683, 3688, 3692, 3697, 3701, 3707, 3712, 3718, 3722, 3723, 3724, 3726, + 3727, 3728, 3731, 3736, 3737, 3738, 3739, 3740, 3741, 3742, 3743, 3745, 3747, 3748, 3750, 3751, 3752, 3753, 3754, 3755, 3756, 3757, 3759, 3760, + 3761, 3762, 3764, 3765, 3766, 3767, 3768, 3769, 3770, 3771, 3772 ] }, {"title": "Visualization", "description": "", "tags": [], "problems": [1, 2, 11, 1431, 1679, 1768, 1798, 2215, 3603, 3622, 3623]}, @@ -176,13 +176,13 @@ 3475, 3477, 3478, 3479, 3480, 3482, 3483, 3484, 3485, 3486, 3487, 3488, 3489, 3490, 3492, 3493, 3494, 3495, 3497, 3498, 3499, 3500, 3501, 3502, 3503, 3504, 3505, 3507, 3508, 3509, 3510, 3513, 3514, 3515, 3516, 3517, 3518, 3519, 3521, 3523, 3524, 3525, 3527, 3528, 3529, 3530, 3531, 3532, 3533, 3534, 3536, 3537, 3538, 3539, 3541, 3542, 3543, 3544, 3545, 3546, 3547, 3548, 3550, 3551, 3552, 3553, 3554, 3556, 3557, 3558, 3559, 3560, - 3561, 3562, 3563, 3564, 3566, 3567, 3568, 3569, 3570, 3572, 3573, 3574, 3575, 3576, 3577, 3578, 3579, 3580, 3582, 3583, 3584, 3585, 3586, 3587, - 3588, 3589, 3590, 3591, 3592, 3593, 3594, 3597, 3598, 3599, 3600, 3601, 3604, 3605, 3609, 3611, 3612, 3613, 3614, 3615, 3617, 3618, 3619, 3620, - 3621, 3624, 3626, 3627, 3628, 3629, 3630, 3633, 3634, 3635, 3636, 3637, 3638, 3639, 3640, 3642, 3643, 3644, 3645, 3646, 3648, 3649, 3650, 3651, - 3652, 3653, 3654, 3655, 3657, 3658, 3659, 3660, 3661, 3664, 3665, 3666, 3669, 3670, 3671, 3673, 3674, 3675, 3676, 3677, 3679, 3680, 3681, 3684, - 3685, 3686, 3689, 3690, 3691, 3693, 3694, 3695, 3698, 3699, 3700, 3702, 3703, 3704, 3705, 3706, 3708, 3709, 3710, 3711, 3713, 3714, 3715, 3716, - 3717, 3719, 3720, 3721, 3725, 3729, 3730, 3732, 3733, 3734, 3735, 3744, 3746, 3749, 3758, 3763, 3773, 3774, 3775, 3776, 3777, 3778, 3779, 3780, - 3781, 3782, 3783, 3784, 3785, 3786, 3787, 3788, 3789, 3790, 3791, 3792, 3793, 3794, 3795, 3796, 3797, 3798, 3799 + 3561, 3562, 3563, 3564, 3566, 3567, 3568, 3569, 3570, 3572, 3573, 3574, 3575, 3576, 3577, 3578, 3579, 3580, 3582, 3584, 3585, 3586, 3587, 3588, + 3589, 3590, 3591, 3592, 3593, 3594, 3597, 3598, 3599, 3600, 3601, 3604, 3605, 3609, 3611, 3612, 3613, 3614, 3615, 3617, 3618, 3619, 3620, 3621, + 3624, 3626, 3627, 3628, 3629, 3630, 3633, 3634, 3635, 3636, 3637, 3638, 3639, 3640, 3642, 3643, 3644, 3645, 3646, 3648, 3649, 3650, 3651, 3652, + 3653, 3654, 3655, 3657, 3658, 3659, 3660, 3661, 3664, 3665, 3666, 3669, 3670, 3671, 3673, 3674, 3675, 3676, 3677, 3679, 3680, 3681, 3684, 3685, + 3686, 3689, 3690, 3691, 3693, 3694, 3695, 3698, 3699, 3700, 3702, 3703, 3704, 3705, 3706, 3708, 3709, 3710, 3711, 3713, 3714, 3715, 3716, 3717, + 3719, 3720, 3721, 3725, 3729, 3730, 3732, 3733, 3734, 3735, 3744, 3746, 3749, 3758, 3763, 3773, 3774, 3775, 3776, 3777, 3778, 3779, 3780, 3781, + 3782, 3783, 3784, 3785, 3786, 3787, 3788, 3789, 3790, 3791, 3792, 3793, 3794, 3795, 3796, 3797, 3798, 3799 ], "premium": [ 27, 156, 157, 158, 159, 161, 163, 170, 186, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 259, 261, 265, 266, 267, 269, diff --git a/explanations/3583/en.md b/explanations/3583/en.md new file mode 100644 index 0000000..df47409 --- /dev/null +++ b/explanations/3583/en.md @@ -0,0 +1,56 @@ +## Explanation + +### Strategy (The "Why") + +**Restate the problem:** We need to count special triplets (i, j, k) where i < j < k, nums[i] == nums[j] * 2, and nums[k] == nums[j] * 2. In other words, for each middle element j, we need to count how many i < j have nums[i] == target and how many k > j have nums[k] == target, where target = nums[j] * 2. + +**1.1 Constraints & Complexity:** +- Input size: `3 <= n <= 10^5`, `0 <= nums[i] <= 10^5` +- **Time Complexity:** O(n) - single pass through array with hash map operations +- **Space Complexity:** O(n) for hash maps storing frequencies +- **Edge Case:** If no triplets exist, return 0 + +**1.2 High-level approach:** +We process each position j as the middle element. We maintain two frequency maps: one for elements before j (freq_before) and one for elements after j (freq_after). For each j, we count how many i < j have nums[i] == target and how many k > j have nums[k] == target, then multiply these counts. + +![Frequency counting for triplets visualization](https://assets.leetcode.com/static_assets/others/frequency-counting-triplets.png) + +**1.3 Brute force vs. optimized strategy:** +- **Brute Force:** Check all triplets (i, j, k) where i < j < k, which is O(n³) +- **Optimized Strategy:** For each j, use hash maps to count valid i and k positions in O(1), achieving O(n) time +- **Emphasize the optimization:** Hash maps allow us to count frequencies before and after each position efficiently without nested loops + +**1.4 Decomposition:** +1. Initialize freq_before (empty) and freq_after (contains all elements initially) +2. Process each position j from left to right +3. Remove nums[j] from freq_after (since j is no longer "after") +4. Calculate target = nums[j] * 2 +5. Count valid i positions (freq_before[target]) and valid k positions (freq_after[target]) +6. Multiply counts and add to result (modulo 10^9 + 7) +7. Add nums[j] to freq_before for future j positions + +### Steps (The "How") + +**2.1 Initialization & Example Setup:** +Let's use the example: `nums = [6, 3, 6]` +- Initialize: `freq_before = {}`, `freq_after = {6: 2, 3: 1}`, `res = 0`, `MOD = 10^9 + 7` + +**2.2 Start Processing:** +We iterate through each position j from 0 to n-1. + +**2.3 Trace Walkthrough:** + +| j | nums[j] | Remove from freq_after | target | freq_before[target] | freq_after[target] | Count | res | +|---|---------|------------------------|--------|---------------------|-------------------|-------|-----| +| 0 | 6 | freq_after = {6: 1, 3: 1} | 12 | 0 | 0 | 0 * 0 = 0 | 0 | +| 0 | - | Add to freq_before | - | freq_before = {6: 1} | - | - | 0 | +| 1 | 3 | freq_after = {6: 1} | 6 | 1 (from freq_before) | 1 (from freq_after) | 1 * 1 = 1 | 1 | +| 1 | - | Add to freq_before | - | freq_before = {6: 1, 3: 1} | - | - | 1 | +| 2 | 6 | freq_after = {} | 12 | 0 | 0 | 0 * 0 = 0 | 1 | + +**2.4 Increment and Loop:** +For each j, we update frequency maps and count triplets where j is the middle element. + +**2.5 Return Result:** +After processing all positions, `res = 1`, which is the number of special triplets. The triplet is (0, 1, 2) where nums[0] = 6 = 3 * 2 and nums[2] = 6 = 3 * 2. + diff --git a/explanations/3760/en.md b/explanations/3760/en.md index b97fb81..62764e6 100644 --- a/explanations/3760/en.md +++ b/explanations/3760/en.md @@ -2,55 +2,50 @@ ### Strategy (The "Why") -**Restate the problem:** We need to convert string `source` to `target` with minimum cost using substring conversions. Operations must be disjoint or identical (can't overlap partially). +**Restate the problem:** We need to find the maximum number of substrings we can split a string into such that each substring starts with a distinct character. No two substrings can start with the same character. **1.1 Constraints & Complexity:** -- Input size: `1 <= source.length == target.length <= 1000`, `1 <= original.length <= 100` -- **Time Complexity:** O(m³ + n² * m) where m is number of unique strings and n is string length, due to Floyd-Warshall and DP -- **Space Complexity:** O(m² + n) for distance matrix and DP array -- **Edge Case:** If source == target, return 0 +- Input size: `1 <= s.length <= 10^5` +- **Time Complexity:** O(n) - single pass to count distinct characters +- **Space Complexity:** O(1) - using a set of at most 26 characters (lowercase English letters) +- **Edge Case:** If all characters are the same (e.g., "aaaa"), we can only have 1 substring **1.2 High-level approach:** -We model substring conversions as a graph, use Floyd-Warshall to find shortest paths, then use dynamic programming to find the minimum cost to convert prefixes of the source string. +The key insight is that each substring must start with a distinct character. Since we can only use each starting character once, the maximum number of substrings equals the number of distinct characters in the string. -![DP with substring matching visualization](https://assets.leetcode.com/static_assets/others/dp-substring-matching.png) +![Distinct characters visualization](https://assets.leetcode.com/static_assets/others/distinct-characters.png) **1.3 Brute force vs. optimized strategy:** -- **Brute Force:** Try all possible sequences of substring conversions, which is exponential. -- **Optimized Strategy:** Precompute shortest paths between all string pairs using Floyd-Warshall, then use DP where dp[i] = minimum cost to convert first i characters. +- **Brute Force:** Try all possible ways to split the string, which is exponential +- **Optimized Strategy:** Simply count distinct characters - each distinct character can start exactly one substring, so the answer is the count of distinct characters +- **Emphasize the optimization:** The constraint that each substring must start with a distinct character directly limits the answer to the number of distinct characters **1.4 Decomposition:** -1. Assign unique IDs to all unique strings in original and changed arrays -2. Build graph and run Floyd-Warshall to find shortest conversion costs -3. Use DP: dp[i] = min cost to convert source[0:i] to target[0:i] -4. For each position, try all possible substring conversions ending there -5. Return dp[n] or -1 if impossible +1. Count the number of distinct characters in the string +2. Since each substring must start with a distinct character, and we can only use each character once as a start +3. The maximum number of substrings equals the number of distinct characters +4. Return the count ### Steps (The "How") **2.1 Initialization & Example Setup:** -Let's use the example: `source = "abcd"`, `target = "acbe"`, `original = ["a","b","c","c","e","d"]`, `changed = ["b","c","b","e","b","e"]`, `cost = [2,5,5,1,2,20]` -- Map strings to IDs: a→0, b→1, c→2, e→3, d→4 -- Build graph and run Floyd-Warshall +Let's use the example: `s = "abab"` +- Distinct characters: 'a' and 'b' (2 distinct characters) +- We can split into: "a" and "bab" (starts with 'a' and 'b') -**2.2 Start Processing:** -We initialize dp[0] = 0, then process each position. +**2.2 Start Checking:** +We count distinct characters in the string. **2.3 Trace Walkthrough:** -Processing `source = "abcd"` to `target = "acbe"`: -| i | source[0:i] | target[0:i] | Options | dp[i] | -|---|-------------|-------------|---------|-------| -| 0 | "" | "" | Base case | 0 | -| 1 | "a" | "a" | No change (dp[0] + 0) | 0 | -| 2 | "ab" | "ac" | Try "b"→"c": dp[1] + cost(b→c) = 0 + 5 = 5 | 5 | -| 3 | "abc" | "acb" | Try "c"→"b": dp[2] + cost(c→b) = 5 + 5 = 10
Or "bc"→"cb": need to check if exists | 10 | -| 4 | "abcd" | "acbe" | Try "d"→"e": dp[3] + cost(d→e) = 10 + 20 = 30 | 30 | - -Actually, we need to check all substring conversions. For position 2, we can convert "b" to "c" at cost 5. For position 3, we convert "c" to "b" at cost 5 (or find better path). For position 4, we convert "d" to "e" at cost 20. Total: 5 + 5 + 20 = 30, but the example says 28, so there must be a better path. +| String | Distinct Characters | Count | Maximum Substrings | +|--------|-------------------|-------|-------------------| +| "abab" | {'a', 'b'} | 2 | 2 | +| "abcd" | {'a', 'b', 'c', 'd'} | 4 | 4 | +| "aaaa" | {'a'} | 1 | 1 | **2.4 Increment and Loop:** -For each position i, we try all possible substring conversions ending at i and take the minimum cost. +We iterate through the string once to collect all distinct characters in a set. **2.5 Return Result:** -After processing, `dp[4] = 28` (using optimal conversions), which is the minimum cost to convert "abcd" to "acbe". +For "abab", we have 2 distinct characters, so the maximum number of substrings is 2. We can split as "a" + "bab" where "a" starts with 'a' and "bab" starts with 'b'. diff --git a/explanations/3761/en.md b/explanations/3761/en.md index 673642f..ca13f12 100644 --- a/explanations/3761/en.md +++ b/explanations/3761/en.md @@ -2,62 +2,57 @@ ### Strategy (The "Why") -**Restate the problem:** We need to count valid paths in a tree where exactly one prime number appears on the path. A path (a,b) is valid if there is exactly one prime in the node labels along the path from a to b. +**Restate the problem:** We need to find the minimum absolute distance between indices of any mirror pair. A mirror pair (i, j) exists when reverse(nums[i]) == nums[j], where reverse(x) reverses the digits of x (removing leading zeros). **1.1 Constraints & Complexity:** -- Input size: `1 <= n <= 10^5` -- **Time Complexity:** O(n) for sieve + O(n) for DFS = O(n) -- **Space Complexity:** O(n) for the tree and DP arrays -- **Edge Case:** If a path contains no primes or more than one prime, it's not valid +- Input size: `1 <= nums.length <= 10^5`, `1 <= nums[i] <= 10^9` +- **Time Complexity:** O(n) - single pass through array with hash map lookups +- **Space Complexity:** O(n) for the hash map storing reversed values +- **Edge Case:** If no mirror pairs exist, return -1 **1.2 High-level approach:** -We use tree DP where dp[node][0] counts paths with 0 primes and dp[node][1] counts paths with 1 prime, starting from that node going downward. We count valid paths by combining paths from different subtrees. +We scan the array left to right, maintaining a hash map that stores the most recent index for each reversed value. For each number, we check if its value matches any reversed value we've seen, and track the minimum distance. -![Tree DP visualization](https://assets.leetcode.com/static_assets/others/tree-dp.png) +![Hash map for mirror pairs visualization](https://assets.leetcode.com/static_assets/others/hash-map-mirror-pairs.png) **1.3 Brute force vs. optimized strategy:** -- **Brute Force:** Check all O(n²) pairs of nodes and count primes on each path, which is O(n³). -- **Optimized Strategy:** Use tree DP to count paths in O(n) time. For each node, we combine paths from its children, counting how many paths pass through the current node. +- **Brute Force:** Check all pairs (i, j) where i < j, which is O(n²) +- **Optimized Strategy:** Use hash map to track reversed values as we scan, checking matches in O(1) per element, achieving O(n) time +- **Emphasize the optimization:** Hash map allows us to find matches instantly without checking all previous elements **1.4 Decomposition:** -1. Use Sieve of Eratosthenes to identify prime numbers -2. Build the tree from edges -3. Perform DFS with DP: dp[node][0] = paths with 0 primes, dp[node][1] = paths with 1 prime -4. When processing a node, count valid paths by combining: (node has 1 prime, child has 0) or (node has 0, child has 1) -5. Update DP values based on whether current node is prime +1. Define helper function to reverse digits of a number (removing leading zeros) +2. Scan array left to right +3. For each number, check if current value matches any reversed value in hash map +4. If match found, update minimum distance +5. Store current index under the reversed value of current number for future matches ### Steps (The "How") **2.1 Initialization & Example Setup:** -Let's use the example: `n = 5`, `edges = [[1,2],[1,3],[2,4],[2,5]]` -- Primes: 2, 3, 5 (1 is not prime) -- Build tree: 1 connected to 2,3; 2 connected to 4,5 -- Initialize dp arrays for all nodes +Let's use the example: `nums = [12, 21, 45, 33, 54]` +- Initialize: `seen = {}`, `res = inf` +- We'll process each number and track reversed values -**2.2 Start DFS:** -We perform DFS starting from node 1 (root). +**2.2 Start Checking:** +We iterate through each number in the array. **2.3 Trace Walkthrough:** -Processing the tree with DFS: -| Node | Is Prime? | dp[node] Before | Children | Valid Paths Found | dp[node] After | -|------|-----------|-----------------|----------|-------------------|----------------| -| 4 | No | [1,0] | None | 0 | [1,0] | -| 5 | Yes | [0,1] | None | 0 | [0,1] | -| 2 | Yes | [0,1] | 4,5 | 1*1 + 0*0 = 1 | [1,1] | -| 3 | Yes | [0,1] | None | 0 | [0,1] | -| 1 | No | [1,0] | 2,3 | 0*1 + 1*1 + 1*0 + 0*1 = 2 | [3,2] | +| Index | Number | Reversed | Check Match | seen Before | Min Distance | seen After | +|-------|--------|----------|-------------|-------------|--------------|------------| +| 0 | 12 | 21 | 12 in seen? No | {} | inf | {21: 0} | +| 1 | 21 | 12 | 21 in seen? No | {21: 0} | inf | {21: 0, 12: 1} | +| 2 | 45 | 54 | 45 in seen? No | {21: 0, 12: 1} | inf | {21: 0, 12: 1, 54: 2} | +| 3 | 33 | 33 | 33 in seen? No | {21: 0, 12: 1, 54: 2} | inf | {21: 0, 12: 1, 54: 2, 33: 3} | +| 4 | 54 | 45 | 54 in seen? No | {21: 0, 12: 1, 54: 2, 33: 3} | inf | {21: 0, 12: 1, 54: 2, 33: 3, 45: 4} | -Valid paths: -- (1,2): path contains prime 2 → valid -- (1,3): path contains prime 3 → valid -- (1,4): path contains prime 2 → valid -- (2,4): path contains prime 2 → valid +Wait, let me reconsider. At index 1, we have num=21. We check if 21 is in seen. But we stored reversed(12)=21 at index 0. So 21 matches! Distance = 1-0 = 1. -Total: 4 valid paths +Actually, the logic is: for each num, we check if num itself is in seen (meaning we've seen its reverse before). Then we store reversed(num) for future checks. **2.4 Increment and Loop:** -During DFS, when we process a child, we count valid paths passing through the current node by combining dp values, then update the current node's dp values. +For each number, we check for matches, update minimum distance, and store the reversed value for future matches. **2.5 Return Result:** -After DFS completes, `res = 4`, which is the number of valid paths with exactly one prime number. +After processing, the minimum distance is 1 (from indices 0 and 1: reverse(12)=21 matches nums[1]=21). If no matches found, return -1. diff --git a/explanations/3771/en.md b/explanations/3771/en.md index cea3c19..d34141d 100644 --- a/explanations/3771/en.md +++ b/explanations/3771/en.md @@ -6,49 +6,47 @@ **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 +- **Time Complexity:** O(n log n) using prefix sums and binary search - for each room j, we use binary search to count valid starting positions - **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. +We reverse the approach: instead of checking each starting position, for each room j we count how many starting positions i <= j would result in earning a point at room j. We use prefix sums and binary search to efficiently count valid starting positions. ![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 +- **Optimized Strategy:** For each room j, use binary search on prefix sums to count valid starting positions i where prefix[i] >= threshold, achieving O(n log n) +- **Emphasize the optimization:** Binary search on non-decreasing prefix array allows O(log n) counting per room instead of O(n) linear scan **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 +1. Compute prefix sums for damage array +2. For each room j, calculate threshold = requirement[j] - hp + prefix[j+1] +3. Use binary search to find first index i where prefix[i] >= threshold +4. Count all starting positions from that index to j (all satisfy the condition) +5. Sum counts across all rooms to get total score ### 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) +- Compute prefix sums: `prefix = [0, 3, 9, 16]` +- For each room j, we'll count valid starting positions i <= j **2.2 Start Processing:** -We iterate through each starting position. +We iterate through each room j and use binary search to count valid starting positions. **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 | +| j | requirement[j] | threshold | Binary Search Result | Valid i Count | res | +|---|----------------|-----------|---------------------|---------------|-----| +| 0 | 4 | 4 - 11 + 3 = -4 | prefix[0]=0 >= -4, idx=0 | j+1 - 0 = 1 | 1 | +| 1 | 2 | 2 - 11 + 9 = 0 | prefix[0]=0 >= 0, idx=0 | j+1 - 0 = 2 | 3 | +| 2 | 5 | 5 - 11 + 16 = 10 | prefix[2]=9 < 10, prefix[3]=16 >= 10, idx=3 | j+1 - 3 = 0 | 3 | **2.4 Increment and Loop:** -After processing all starting positions, we sum the scores. +For each room j, we calculate threshold, use binary search to find the first valid starting position, and count all valid positions from that index to j. **2.5 Return Result:** -Total score = score(0) + score(1) + score(2) = 2 + 1 + 0 = 3, which is the result. +After processing all rooms, total score = 3, which matches the expected result. diff --git a/explanations/3772/en.md b/explanations/3772/en.md index 025a3f7..fce58e1 100644 --- a/explanations/3772/en.md +++ b/explanations/3772/en.md @@ -6,25 +6,25 @@ **1.1 Constraints & Complexity:** - Input size: `2 <= n <= 10^5` -- **Time Complexity:** O(n²) for naive approach, can be optimized with tree DP +- **Time Complexity:** O(n) using rerooting DP - first DFS computes subtree scores, second DFS reroots in O(n) - **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. +We use tree dynamic programming with efficient rerooting. First, we compute subtree scores from an arbitrary root. Then, we use rerooting to compute answers for all nodes in O(n) time by efficiently transferring parent contributions to children. ![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 +- **Brute Force:** For each node as root, perform DFS separately, which is O(n²) +- **Optimized Strategy:** Use rerooting DP - compute subtree scores once, then efficiently reroot to all nodes in O(n) time +- **Emphasize the optimization:** Rerooting allows us to compute all root answers in O(n) instead of O(n²) by reusing subtree information **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 +2. First DFS: Compute subtree scores from root 0 (down[node] = max score of subtree rooted at node) +3. Second DFS: Reroot efficiently - when moving from parent to child, calculate parent's contribution without child and add it to child's score +4. Use rerooting formula: ans[child] = down[child] + max(0, ans[parent] - max(0, down[child])) 5. Return the array of maximum scores for each node ### Steps (The "How") @@ -34,19 +34,27 @@ 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.2 First DFS (Compute Subtree Scores):** +We perform DFS from root 0 to compute down[node] = max score of subtree rooted at node. -**2.3 Trace Walkthrough:** +**2.3 Trace Walkthrough (First DFS):** -| 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 | +| Node | Parent | Children | Node Score | Child Scores | down[node] | +|------|--------|----------|------------|--------------|------------| +| 2 | 1 | None | +1 | - | 1 | +| 1 | 0 | 2 | -1 | down[2]=1 (>0) | -1 + 1 = 0 | +| 0 | -1 | 1 | +1 | down[1]=0 (≤0) | 1 | -**2.4 Increment and Loop:** -After processing all roots, we have maximum scores for each node. +**2.4 Second DFS (Rerooting):** +We reroot from parent to child efficiently. For node 0 (root), ans[0] = down[0] = 1. -**2.5 Return Result:** -The result array is `[1, 1, 1]`, representing the maximum score for each node. +**2.5 Trace Walkthrough (Rerooting to Node 1):** +- parent_contrib = ans[0] - max(0, down[1]) = 1 - 0 = 1 +- ans[1] = down[1] + max(0, 1) = 0 + 1 = 1 + +**2.6 Trace Walkthrough (Rerooting to Node 2):** +- parent_contrib = ans[1] - max(0, down[2]) = 1 - 1 = 0 +- ans[2] = down[2] + max(0, 0) = 1 + 0 = 1 + +**2.7 Return Result:** +The result array is `[1, 1, 1]`, representing the maximum score for each node when it is the root. diff --git a/solutions/3583/01.py b/solutions/3583/01.py new file mode 100644 index 0000000..ab7676b --- /dev/null +++ b/solutions/3583/01.py @@ -0,0 +1,42 @@ +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 + diff --git a/solutions/3760/01.py b/solutions/3760/01.py index 4cbb3f1..cea514d 100644 --- a/solutions/3760/01.py +++ b/solutions/3760/01.py @@ -1,59 +1,7 @@ class Solution: - def minimumCost(self, source: str, target: str, original: List[str], changed: List[str], cost: List[int]) -> int: - # Assign unique IDs to all unique strings - string_to_id = {} - id_counter = 0 - - all_strings = set(original) | set(changed) - for s in all_strings: - if s not in string_to_id: - string_to_id[s] = id_counter - id_counter += 1 - - n_strings = len(string_to_id) - INF = float('inf') - - # Build graph with Floyd-Warshall - dist = [[INF] * n_strings for _ in range(n_strings)] - - # Initialize: same string costs 0 - for i in range(n_strings): - dist[i][i] = 0 - - # Add edges - for i in range(len(original)): - orig_id = string_to_id[original[i]] - changed_id = string_to_id[changed[i]] - cost_val = cost[i] - dist[orig_id][changed_id] = min(dist[orig_id][changed_id], cost_val) - - # Floyd-Warshall - for k in range(n_strings): - for i in range(n_strings): - for j in range(n_strings): - if dist[i][k] != INF and dist[k][j] != INF: - dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]) - - # DP: dp[i] = minimum cost to convert first i characters - n = len(source) - dp = [INF] * (n + 1) - dp[0] = 0 - - for i in range(1, n + 1): - # Option 1: No change if characters match - if source[i-1] == target[i-1]: - dp[i] = min(dp[i], dp[i-1]) - - # Option 2: Try all possible substring conversions ending at i - for j in range(i): - substr_src = source[j:i] - substr_tgt = target[j:i] - - if substr_src in string_to_id and substr_tgt in string_to_id: - src_id = string_to_id[substr_src] - tgt_id = string_to_id[substr_tgt] - - if dist[src_id][tgt_id] != INF: - dp[i] = min(dp[i], dp[j] + dist[src_id][tgt_id]) - - return dp[n] if dp[n] != INF else -1 + def maxDistinct(self, s: str) -> int: + # Count distinct characters in the string + # Each substring must start with a distinct character + # So the answer is the number of distinct characters + distinct_chars = len(set(s)) + return distinct_chars diff --git a/solutions/3761/01.py b/solutions/3761/01.py index c5c9b12..f2da208 100644 --- a/solutions/3761/01.py +++ b/solutions/3761/01.py @@ -1,48 +1,21 @@ class Solution: - def countPaths(self, n: int, edges: List[List[int]]) -> int: - # Sieve of Eratosthenes to find primes - is_prime = [True] * (n + 1) - is_prime[0] = is_prime[1] = False + def minMirrorPairDistance(self, nums: List[int]) -> int: + def reverse_num(n): + # Reverse digits, removing leading zeros + return int(str(n)[::-1]) - p = 2 - while p * p <= n: - if is_prime[p]: - for i in range(p * p, n + 1, p): - is_prime[i] = False - p += 1 + # Map: reversed value -> most recent index + seen = {} + res = float('inf') - # Build tree - from collections import defaultdict - graph = defaultdict(list) - for u, v in edges: - graph[u].append(v) - graph[v].append(u) - - # DP: dp[node][0] = paths with 0 primes, dp[node][1] = paths with 1 prime - dp = [[0, 0] for _ in range(n + 1)] - res = 0 - - def dfs(node, parent): - nonlocal res + for i, num in enumerate(nums): + reversed_val = reverse_num(num) - if is_prime[node]: - dp[node][1] = 1 - else: - dp[node][0] = 1 + # Check if current number matches any reversed value we've seen + if num in seen: + res = min(res, i - seen[num]) - for child in graph[node]: - if child != parent: - dfs(child, node) - # Count paths passing through current node - # Path with 1 prime: (node has 1 prime, child has 0) or (node has 0, child has 1) - res += dp[node][1] * dp[child][0] + dp[node][0] * dp[child][1] - - # Update dp for current node - if is_prime[node]: - dp[node][1] += dp[child][0] - else: - dp[node][0] += dp[child][0] - dp[node][1] += dp[child][1] + # Store current index under the reversed value + seen[reversed_val] = i - dfs(1, 0) - return res + return res if res != float('inf') else -1 diff --git a/solutions/3766/01.py b/solutions/3766/01.py index 5212cc1..c9c53e3 100644 --- a/solutions/3766/01.py +++ b/solutions/3766/01.py @@ -13,11 +13,18 @@ def is_binary_palindrome(n): res = [] for num in nums: - # Find closest palindrome + # Use binary search to find closest palindrome + import bisect + idx = bisect.bisect_left(palindromes, num) + min_ops = float('inf') - for pal in palindromes: - ops = abs(num - pal) - min_ops = min(min_ops, ops) + # 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/3770/01.py b/solutions/3770/01.py index 94447c8..9a507a7 100644 --- a/solutions/3770/01.py +++ b/solutions/3770/01.py @@ -12,16 +12,19 @@ def largestPrime(self, n: int) -> int: # Get all primes primes = [i for i in range(2, n + 1) if is_prime[i]] - # Compute consecutive prime sums starting from 2 + if not primes: + return 0 + + # Only check consecutive sums starting from 2 (first prime) 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) + current_sum = 0 + # Start from index 0 (which is prime 2) + for i in range(len(primes)): + current_sum += primes[i] + 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 index 30e696d..a8abd5a 100644 --- a/solutions/3771/01.py +++ b/solutions/3771/01.py @@ -7,15 +7,20 @@ def totalScore(self, hp: int, damage: List[int], requirement: List[int]) -> int: for i in range(n): prefix[i + 1] = prefix[i] + damage[i] - # For each starting position i, calculate score + # 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 - 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 + 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 + # Since prefix is non-decreasing, we can use bisect_left + 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/3772/01.py b/solutions/3772/01.py index 82432bd..1c7ceae 100644 --- a/solutions/3772/01.py +++ b/solutions/3772/01.py @@ -1,35 +1,50 @@ class Solution: - def maxSubgraphScore(self, n: int, edges: List[List[int]], good: List[int]) -> List[int]: + 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 + + # Rerooting DP - O(n) solution + # down[node] = max score of subtree rooted at node + down = [0] * n + + def dfs1(node, parent): node_score = 1 if good[node] else -1 - - # Best score including this node and its children - best = node_score + score = node_score + for child in graph[node]: if child != parent: - child_score = dfs(child, node) - # Include child if it improves the score + child_score = dfs1(child, node) 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 + score += child_score + + down[node] = score + return score + + dfs1(0, -1) + + # ans[node] = max score when node is root + ans = [0] * n + ans[0] = down[0] + + def dfs2(node, parent): + if parent != -1: + # Standard rerooting formula: + # ans[child] = down[child] + max(0, ans[parent] - max(0, down[child])) + # But we need to account for the fact that ans[parent] includes down[node] + # So parent's contribution without node = ans[parent] - max(0, down[node]) + parent_contrib = ans[parent] - max(0, down[node]) + ans[node] = down[node] + max(0, parent_contrib) + + for child in graph[node]: + if child != parent: + dfs2(child, node) + + dfs2(0, -1) + return ans From 3089befe46de4c87b649de0fe4df50265f69a843 Mon Sep 17 00:00:00 2001 From: vikahaze Date: Tue, 9 Dec 2025 07:13:48 +0200 Subject: [PATCH 2/2] Remove failed problems 3762 and 3769 from repository --- data/book-sets.json | 2 +- explanations/3762/en.md | 52 ----------------------------------------- explanations/3769/en.md | 50 --------------------------------------- solutions/3762/01.py | 14 ----------- solutions/3769/01.py | 11 --------- 5 files changed, 1 insertion(+), 128 deletions(-) delete mode 100644 explanations/3762/en.md delete mode 100644 explanations/3769/en.md delete mode 100644 solutions/3762/01.py delete mode 100644 solutions/3769/01.py diff --git a/data/book-sets.json b/data/book-sets.json index 63672d9..13e5a4b 100644 --- a/data/book-sets.json +++ b/data/book-sets.json @@ -63,7 +63,7 @@ 2879, 2884, 2888, 2894, 2942, 3100, 3110, 3133, 3164, 3190, 3197, 3228, 3291, 3320, 3351, 3380, 3381, 3413, 3424, 3432, 3444, 3471, 3512, 3522, 3583, 3602, 3603, 3606, 3607, 3608, 3622, 3623, 3625, 3663, 3668, 3678, 3683, 3688, 3692, 3697, 3701, 3707, 3712, 3718, 3722, 3723, 3724, 3726, 3727, 3728, 3731, 3736, 3737, 3738, 3739, 3740, 3741, 3742, 3743, 3745, 3747, 3748, 3750, 3751, 3752, 3753, 3754, 3755, 3756, 3757, 3759, 3760, - 3761, 3762, 3764, 3765, 3766, 3767, 3768, 3769, 3770, 3771, 3772 + 3761, 3764, 3765, 3766, 3767, 3768, 3770, 3771, 3772 ] }, {"title": "Visualization", "description": "", "tags": [], "problems": [1, 2, 11, 1431, 1679, 1768, 1798, 2215, 3603, 3622, 3623]}, diff --git a/explanations/3762/en.md b/explanations/3762/en.md deleted file mode 100644 index b681647..0000000 --- a/explanations/3762/en.md +++ /dev/null @@ -1,52 +0,0 @@ -## Explanation - -### Strategy (The "Why") - -**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` -- **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:** -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. - -![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 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. 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 an empty set: `distinct_greater = set()` - -**2.2 Start Checking:** -We iterate through each number in the array. - -**2.3 Trace Walkthrough:** - -| 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:** -After processing all numbers, we have `distinct_greater = {5, 4}`. - -**2.5 Return Result:** -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/3769/en.md b/explanations/3769/en.md deleted file mode 100644 index 7778dd7..0000000 --- a/explanations/3769/en.md +++ /dev/null @@ -1,50 +0,0 @@ -## 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/solutions/3762/01.py b/solutions/3762/01.py deleted file mode 100644 index d4f3367..0000000 --- a/solutions/3762/01.py +++ /dev/null @@ -1,14 +0,0 @@ -class Solution: - def minOperations(self, nums: List[int], k: int) -> int: - # Check if any element is less than k (impossible case) - if any(num < k for num in nums): - return -1 - - # Count distinct numbers greater than k - distinct_greater = set() - for num in nums: - if num > k: - distinct_greater.add(num) - - res = len(distinct_greater) - return res diff --git a/solutions/3769/01.py b/solutions/3769/01.py deleted file mode 100644 index acc311c..0000000 --- a/solutions/3769/01.py +++ /dev/null @@ -1,11 +0,0 @@ -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