|
| 1 | +# [Problem 1262: Greatest Sum Divisible by Three](https://leetcode.com/problems/greatest-sum-divisible-by-three/description/?envType=daily-question) |
| 2 | + |
| 3 | +## Initial thoughts (stream-of-consciousness) |
| 4 | +I want the largest sum from some subset of the array such that the sum % 3 == 0. The simplest idea is to take as many numbers as possible — i.e., try to use the total sum, and if total % 3 != 0, remove the smallest possible amount to make it divisible by 3. So compute total = sum(nums). If total % 3 == 0 we're done. Otherwise, depending on remainder r (1 or 2), either remove the smallest single number with num % 3 == r, or remove the smallest two numbers whose remainders sum to r (i.e., two with remainder 3-r). We should track the smallest one or two numbers in each remainder class. This is O(n) and constant extra space. |
| 5 | + |
| 6 | +I also recall a DP approach where we keep dp[0..2] = max sum with remainder 0,1,2 and update for each number, but the greedy "remove minimal" approach is simpler to implement. |
| 7 | + |
| 8 | +Edge cases: if no appropriate numbers exist to remove we must return 0 because we can choose empty subset. Also handle when array has small size (1 or 2). |
| 9 | + |
| 10 | +## Refining the problem, round 2 thoughts |
| 11 | +Refinements: |
| 12 | +- Efficiently track the two smallest numbers for remainder 1 and remainder 2 classes. Initialize them to infinity and update while iterating. |
| 13 | +- After iteration, if total % 3 == 1: candidate removals are min_single_mod1 and sum_of_two_smallest_mod2. If neither exists, answer is 0. Likewise for remainder 2. |
| 14 | +- Complexity: O(n) time, O(1) extra space. |
| 15 | +- Alternative solution: DP with dp = [0, -inf, -inf], then for each num update new_dp[(j + num%3)%3] = max(dp[(j + num%3)%3], dp[j] + num) — also O(n) time and O(1) space. |
| 16 | +- Confirm with examples: [3,6,5,1,8] -> total 23 remainder 2 -> remove smallest mod2 (5) or two mod1s (1 and 8? 8%3=2, so not) so remove 5 get 18. |
| 17 | +- Edge-case: if removal candidates sum to more than total just silly; check existence via infinity sentinel. |
| 18 | + |
| 19 | +## Attempted solution(s) |
| 20 | +```python |
| 21 | +from typing import List |
| 22 | +import math |
| 23 | + |
| 24 | +class Solution: |
| 25 | + def greatestSumDivisibleByThree(self, nums: List[int]) -> int: |
| 26 | + total = sum(nums) |
| 27 | + # track smallest two numbers with remainder 1 and remainder 2 |
| 28 | + inf = float('inf') |
| 29 | + m1_a = m1_b = inf # two smallest with num % 3 == 1 |
| 30 | + m2_a = m2_b = inf # two smallest with num % 3 == 2 |
| 31 | + |
| 32 | + for x in nums: |
| 33 | + r = x % 3 |
| 34 | + if r == 1: |
| 35 | + # update two smallest for remainder 1 |
| 36 | + if x < m1_a: |
| 37 | + m1_b = m1_a |
| 38 | + m1_a = x |
| 39 | + elif x < m1_b: |
| 40 | + m1_b = x |
| 41 | + elif r == 2: |
| 42 | + # update two smallest for remainder 2 |
| 43 | + if x < m2_a: |
| 44 | + m2_b = m2_a |
| 45 | + m2_a = x |
| 46 | + elif x < m2_b: |
| 47 | + m2_b = x |
| 48 | + |
| 49 | + rem = total % 3 |
| 50 | + if rem == 0: |
| 51 | + return total |
| 52 | + |
| 53 | + ans = 0 |
| 54 | + if rem == 1: |
| 55 | + # Option 1: remove smallest single remainder-1 |
| 56 | + cand1 = total - m1_a if m1_a != inf else -math.inf |
| 57 | + # Option 2: remove two smallest remainder-2 |
| 58 | + cand2 = total - (m2_a + m2_b) if m2_a != inf and m2_b != inf else -math.inf |
| 59 | + ans = max(0, int(max(cand1, cand2))) # ensure non-negative |
| 60 | + else: # rem == 2 |
| 61 | + # Option 1: remove smallest single remainder-2 |
| 62 | + cand1 = total - m2_a if m2_a != inf else -math.inf |
| 63 | + # Option 2: remove two smallest remainder-1 |
| 64 | + cand2 = total - (m1_a + m1_b) if m1_a != inf and m1_b != inf else -math.inf |
| 65 | + ans = max(0, int(max(cand1, cand2))) |
| 66 | + |
| 67 | + return ans |
| 68 | +``` |
| 69 | +- Notes: |
| 70 | + - Approach: Greedy removal of the smallest total value necessary to make the sum divisible by 3. Track the two smallest numbers in remainder classes 1 and 2 while scanning once. |
| 71 | + - Time complexity: O(n) where n = len(nums), because we scan the array once. |
| 72 | + - Space complexity: O(1) extra space (only a few variables). |
| 73 | + - Alternative: A DP approach using dp[3] to keep max sums for each remainder class also works and is equally O(n) time, O(1) space. |
0 commit comments