classSolution { publicintmaxSumDivThree(int[] nums) { // 使用 v[0], v[1], v[2] 分别表示 a, b, c List<Integer>[] v = newList[3]; for (inti=0; i < 3; ++i) { v[i] = newArrayList<Integer>(); } for (int num : nums) { v[num % 3].add(num); } Collections.sort(v[1], (a, b) -> b - a); Collections.sort(v[2], (a, b) -> b - a);
publicclassSolution { publicintMaxSumDivThree(int[] nums) { // 使用 v[0], v[1], v[2] 分别表示 a, b, c IList<int>[] v = new IList<int>[3]; for (int i = 0; i < 3; ++i) { v[i] = new List<int>(); } foreach (int num in nums) { v[num % 3].Add(num); } ((List<int>) v[1]).Sort((a, b) => b - a); ((List<int>) v[2]).Sort((a, b) => b - a);
int ans = 0; int lb = v[1].Count, lc = v[2].Count; for (int cntb = lb - 2; cntb <= lb; ++cntb) { if (cntb >= 0) { for (int cntc = lc - 2; cntc <= lc; ++cntc) { if (cntc >= 0 && (cntb - cntc) % 3 == 0) { ans = Math.Max(ans, GetSum(v[1], 0, cntb) + GetSum(v[2], 0, cntc)); } } } } return ans + GetSum(v[0], 0, v[0].Count); }
publicintGetSum(IList<int> list, int start, int end) { int sum = 0; for (int i = start; i < end; ++i) { sum += list[i]; } return sum; } }
[sol1-Python3]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution: defmaxSumDivThree(self, nums: List[int]) -> int: a = [x for x in nums if x % 3 == 0] b = sorted([x for x in nums if x % 3 == 1], reverse=True) c = sorted([x for x in nums if x % 3 == 2], reverse=True)
ans = 0 lb, lc = len(b), len(c) for cntb in [lb - 2, lb - 1, lb]: if cntb >= 0: for cntc in [lc - 2, lc - 1, lc]: if cntc >= 0and (cntb - cntc) % 3 == 0: ans = max(ans, sum(b[:cntb]) + sum(c[:cntc])) return ans + sum(a)
var maxSumDivThree = function(nums) { const v = [[], [], []]; for (const num of nums) { v[num % 3].push(num); } v[1].sort((a, b) => b - a); v[2].sort((a, b) => b - a);
let ans = 0; const lb = v[1].length; const lc = v[2].length; for (let cntb = lb - 2; cntb <= lb; ++cntb) { if (cntb >= 0) { for (let cntc = lc - 2; cntc <= lc; ++cntc) { if (cntc >= 0 && (cntb - cntc) % 3 === 0) { ans = Math.max(ans, getSum(v[1], 0, cntb) + getSum(v[2], 0, cntc)); } } } } return ans + getSum(v[0], 0, v[0].length); }
constgetSum = (list, start, end) => { let sum = 0; for (let i = start; i < end; ++i) { sum += list[i]; } return sum; };
复杂度分析
时间复杂度:O(n \log n),其中 n 是数组 nums 的长度。对 b 和 c 进行排序需要 O(n \log n) 的时间。两重循环枚举的 9 种情况可以看作常数,每一种情况需要 O(n) 的时间进行求和。
空间复杂度:O(n),即为 a,b,c 需要使用的空间。
方法二:贪心 + 逆向思维
在方法一中,我们使用的是「正向思维」,即枚举 b 和 c 中分别选出了多少个数。我们同样也可以使用「逆向思维」,枚举 b 和 c 中分别丢弃了多少个数。
设 tot 是数组 nums 中所有元素的和,此时 tot 会有三种情况:
如果 tot 是 3 的倍数,那么我们不需要丢弃任何数;
如果 tot 模 3 余 1,此时我们有两种选择:要么丢弃 b 中最小的 1 个数,要么丢弃 c 中最小的 2 个数;
如果 tot 模 3 余 2,此时我们有两种选择:要么丢弃 b 中最小的 2 个数,要么丢弃 c 中最小的 1 个数。
我们同样可以对 b 和 c 进行排序,根据 tot 的情况来选出 b 或 c 中最小的 1 或 2 个数。
classSolution { publicintmaxSumDivThree(int[] nums) { // 使用 v[0], v[1], v[2] 分别表示 a, b, c List<Integer>[] v = newList[3]; for (inti=0; i < 3; ++i) { v[i] = newArrayList<Integer>(); } for (int num : nums) { v[num % 3].add(num); } Collections.sort(v[1], (a, b) -> b - a); Collections.sort(v[2], (a, b) -> b - a);
publicclassSolution { publicintMaxSumDivThree(int[] nums) { // 使用 v[0], v[1], v[2] 分别表示 a, b, c IList<int>[] v = new IList<int>[3]; for (int i = 0; i < 3; ++i) { v[i] = new List<int>(); } foreach (int num in nums) { v[num % 3].Add(num); } ((List<int>) v[1]).Sort((a, b) => b - a); ((List<int>) v[2]).Sort((a, b) => b - a);
classSolution: defmaxSumDivThree(self, nums: List[int]) -> int: a = [x for x in nums if x % 3 == 0] b = sorted([x for x in nums if x % 3 == 1], reverse=True) c = sorted([x for x in nums if x % 3 == 2], reverse=True) tot, remove = sum(nums), float("inf")
intmaxSumDivThree(int* nums, int numsSize) { // 使用 v[0], v[1], v[2] 分别表示 a, b, c int n = numsSize; int v[3][n]; int vColSize[3]; memset(vColSize, 0, sizeof(vColSize)); for (int i = 0; i < numsSize; i++) { v[nums[i] % 3][vColSize[nums[i] % 3]++] = nums[i]; } qsort(v[1], vColSize[1], sizeof(int), cmp); qsort(v[2], vColSize[2], sizeof(int), cmp); int tot = 0, remove = INT_MAX; for (int i = 0; i < numsSize; i++) { tot += nums[i]; }
var maxSumDivThree = function(nums) { const v = [[], [], []]; for (const num of nums) { v[num % 3].push(num); } v[1].sort((a, b) => b - a); v[2].sort((a, b) => b - a);
const tot = nums.reduce((sum, num) => sum + num, 0); let remove = Infinity;
classSolution { public: intmaxSumDivThree(vector<int>& nums){ vector<int> f = {0, INT_MIN, INT_MIN}; for (int num: nums) { vector<int> g = f; for (int i = 0; i < 3; ++i) { g[(i + num % 3) % 3] = max(g[(i + num % 3) % 3], f[i] + num); } f = move(g); } return f[0]; } };
[sol3-Java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution { publicintmaxSumDivThree(int[] nums) { int[] f = {0, Integer.MIN_VALUE, Integer.MIN_VALUE}; for (int num : nums) { int[] g = newint[3]; System.arraycopy(f, 0, g, 0, 3); for (inti=0; i < 3; ++i) { g[(i + num % 3) % 3] = Math.max(g[(i + num % 3) % 3], f[i] + num); } f = g; } return f[0]; } }
[sol3-C#]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
publicclassSolution { publicintMaxSumDivThree(int[] nums) { int[] f = {0, int.MinValue, int.MinValue}; foreach (int num in nums) { int[] g = newint[3]; Array.Copy(f, 0, g, 0, 3); for (int i = 0; i < 3; ++i) { g[(i + num % 3) % 3] = Math.Max(g[(i + num % 3) % 3], f[i] + num); } f = g; } return f[0]; } }
[sol3-Python3]
1 2 3 4 5 6 7 8 9
classSolution: defmaxSumDivThree(self, nums: List[int]) -> int: f = [0, -float("inf"), -float("inf")] for num in nums: g = f[:] for i inrange(3): g[(i + num % 3) % 3] = max(g[(i + num % 3) % 3], f[i] + num) f = g return f[0]
[sol3-Golang]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
funcmax(a, b int)int { if a > b { return a } return b }
funcmaxSumDivThree(nums []int)int { f := []int{0, -0x3f3f3f3f, -0x3f3f3f3f} for _, num := range nums { g := make([]int, 3) for i := 0; i < 3; i++ { g[(i + num) % 3] = max(f[(i + num) % 3], f[i] + num) } f = g } return f[0] }
[sol3-C]
1 2 3 4 5 6 7 8 9 10 11 12
intmaxSumDivThree(int* nums, int numsSize) { int f[3] = {0, INT_MIN, INT_MIN}; int g[3] = {0}; for (int j = 0; j < numsSize; j++) { memcpy(g, f, sizeof(f)); for (int i = 0; i < 3; i++) { g[(i + nums[j] % 3) % 3] = fmax(g[(i + nums[j] % 3) % 3], f[i] + nums[j]); } memcpy(f, g, sizeof(f)); } return f[0]; }
[sol3-JavaScript]
1 2 3 4 5 6 7 8 9 10 11
var maxSumDivThree = function(nums) { let f = [0, Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER]; for (const num of nums) { const g = [...f]; for (let i = 0; i < 3; ++i) { g[(i + num % 3) % 3] = Math.max(g[(i + num % 3) % 3], f[i] + num); } f = g; } return f[0]; };