形成三的最大倍数
难度:
标签:
题目描述
代码结果
运行时间: 36 ms, 内存: 16.4 MB
/*
* 题目思路:
* 1. 计算所有数字的总和。
* 2. 如果总和是3的倍数,那么按降序排列所有数字并返回结果。
* 3. 如果总和不是3的倍数,计算余数并尝试移除最少的数字使得总和变为3的倍数。
* 4. 如果无法移除数字使得总和变为3的倍数,则返回空字符串。
* 5. 处理前导零的情况,最终返回结果。
*/
import java.util.*;
import java.util.stream.*;
public class LargestMultipleOfThreeStream {
public String largestMultipleOfThree(int[] digits) {
int sum = Arrays.stream(digits).sum();
Map<Integer, Long> count = Arrays.stream(digits).boxed()
.collect(Collectors.groupingBy(d -> d, Collectors.counting()));
List<Integer> list = Arrays.stream(digits).boxed()
.sorted(Collections.reverseOrder())
.collect(Collectors.toList());
if (sum % 3 == 1) {
if (!removeDigit(count, 1)) {
removeDigit(count, 2);
removeDigit(count, 2);
}
} else if (sum % 3 == 2) {
if (!removeDigit(count, 2)) {
removeDigit(count, 1);
removeDigit(count, 1);
}
}
String result = count.entrySet().stream()
.sorted(Map.Entry.<Integer, Long>comparingByKey().reversed())
.flatMap(e -> Collections.nCopies(e.getValue().intValue(), e.getKey()).stream())
.map(String::valueOf)
.collect(Collectors.joining());
if (result.length() > 0 && result.charAt(0) == '0') return "0";
return result;
}
private boolean removeDigit(Map<Integer, Long> count, int mod) {
for (int i = mod; i < 10; i += 3) {
if (count.getOrDefault(i, 0L) > 0) {
count.put(i, count.get(i) - 1);
return true;
}
}
return false;
}
public static void main(String[] args) {
LargestMultipleOfThreeStream solution = new LargestMultipleOfThreeStream();
int[] digits1 = {8, 1, 9};
int[] digits2 = {8, 6, 7, 1, 0};
int[] digits3 = {1};
int[] digits4 = {0, 0, 0, 0, 0, 0};
System.out.println(solution.largestMultipleOfThree(digits1)); // "981"
System.out.println(solution.largestMultipleOfThree(digits2)); // "8760"
System.out.println(solution.largestMultipleOfThree(digits3)); // ""
System.out.println(solution.largestMultipleOfThree(digits4)); // "0"
}
}
解释
方法:
首先通过计数排序的思路统计每个数字出现的次数,然后计算所有数字的总和。如果总和是3的倍数,那么就可以直接用这些数字组成最大的数。如果不是3的倍数,需要通过删除几个最小的数字来调整总和使其成为3的倍数。具体来说:
1. 计算总和模3的结果,如果余数为1,尝试先删除一个余数为1的数字,如果没有,再尝试删除两个余数为2的数字;如果余数为2,尝试先删除一个余数为2的数字,如果没有,再尝试删除两个余数为1的数字。
2. 删除数字后,按照从大到小的顺序组合剩余的数字,将结果转化为字符串。如果数字中包含0,则确保0只在最后出现,除非结果只有0。
3. 特别注意处理只有0或结果无法形成3的倍数的情况。
时间复杂度:
O(n)
空间复杂度:
O(1)
代码细节讲解
🦆
算法中计算总和时为什么只考虑模3不为0的部分?模3为0的数字对总和有什么影响?
▷🦆
在处理余数为1时,为何首选删除一个余数为1的数字,而非两个余数为2的数字?这样的选择对结果有何优势?
▷🦆
如果在尝试删除指定数量的余数为1或2的数字时没有足够的数字可供删除,这种情况如何处理,会直接返回空字符串吗?
▷🦆
代码中存在`counter[i] -= 1 for i in mod1`的语法错误。应该如何正确实现在找到第一个可用数字后减少其计数器的值?
▷