leetcode
leetcode 1201 ~ 1250
可被三整除的最大和

可被三整除的最大和

难度:

标签:

题目描述

代码结果

运行时间: 41 ms, 内存: 20.4 MB


/*
 * 题目思路:
 * 使用Java Stream API可以简化操作,首先对数组进行分类,然后求出分类后的最小值和总和,根据总和的余数处理不同的情况。
 */
import java.util.Arrays;
public class MaxSumDivThreeStream {
    public int maxSumDivThree(int[] nums) {
        int sum = Arrays.stream(nums).sum();
        int remainder = sum % 3;
        if (remainder == 0) return sum;
        int min1 = Arrays.stream(nums).filter(x -> x % 3 == remainder).min().orElse(Integer.MAX_VALUE);
        int min2 = Arrays.stream(nums).filter(x -> x % 3 == 3 - remainder).min().orElse(Integer.MAX_VALUE);
        if (remainder == 1) {
            return Math.max(sum - min1, sum - min2 - min2);
        } else {
            return Math.max(sum - min2, sum - min1 - min1);
        }
    }
}

解释

方法:

题解的思路主要包括先计算数组所有元素的总和,然后根据总和除以3的余数来调整元素选择,以确保能够获得能被3整除的最大和。首先,计算数组总和s。如果s能够被3整除,直接返回s作为结果。否则,根据s除3的余数(1或2),我们需要调整元素以使总和能被3整除。为此,将数组分成两组,一组的元素除以3余1,另一组除以3余2。如果总和除以3的余数为1,我们尝试移除一个余数为1的最小元素或两个余数为2的最小元素组合。反之,如果余数为2,我们尝试移除一个余数为2的最小元素或两个余数为1的最小元素组合。最终返回调整后的最大总和。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
题解中提到如果总和s除以3的余数为1,可以选择移除一个余数为1的元素或两个余数为2的元素。这种选择策略是否总是保证得到最大的可被三整除的和?
是的,这种选择策略是为了确保从总和中减去最小的可能值,以便使剩余值能被3整除。通过移除一个余数为1的最小元素或两个余数为2的最小元素,我们实际上是在尝试减去总和中最小的、能够改变总和余数的数值组合。这确保了我们从原始总和中减去的值尽可能小,从而使得剩余的和尽可能大。因此,这种策略通常能保证得到最大的可被三整除的和。
🦆
在处理余数为1和2的元素时,题解选择了排序这些元素。排序的目的是什么,有没有更高效的方法来找到最小的几个元素?
排序的目的是使得可以轻松地访问余数为1或2的最小元素,这对于实现上述移除策略是必要的。然而,排序一个列表的时间复杂度为O(n log n),这可能不是最高效的方法。如果只需要找到最小的一个或两个元素,可以使用线性时间的选择算法,例如遍历数组并维护最小值或两个最小值,这样的时间复杂度为O(n),比全数组排序更高效。
🦆
题解中如果数组中没有余数为1的元素时,设置答案为0。这种处理是否意味着在这个情况下无法获得非零的可被三整除的最大和?
这里存在一个逻辑上的疏忽。即使数组中没有余数为1的元素,如果存在至少两个余数为2的元素,通过移除这两个余数为2的元素仍然可以得到一个非零的、可被三整除的最大和。因此,应该检查是否存在两个余数为2的元素,如果存在,则更新答案为 `s - a2[0] - a2[1]`,其中a2[0]和a2[1]是两个最小的余数为2的元素。只有当没有足够的元素来构成一个可以被移除的组合时,答案才应该是0。
🦆
题解中尝试移除元素的策略是基于直接移除最小值。在有多个相同的最小值时,移除哪个具体的元素是否会影响最终结果?
在有多个相同的最小值的情况下,选择移除哪个具体的元素并不会影响最终的结果。因为这些元素的值相同,移除任何一个都会给总和带来相同的减少。因此,只要移除的是正确数量的最小值元素,具体选择哪个相同值的元素移除是没有影响的。

相关问题