给你一个整数数组 digits,你可以通过按 任意顺序 连接其中某些数字来形成 3 的倍数,请你返回所能得到的最大的 3 的倍数。
由于答案可能不在整数数据类型范围内,请以字符串形式返回答案。如果无法得到答案,请返回一个空字符串。返回的结果不应包含不必要的前导零。
示例 1:
输入:digits = [8,1,9]
输出:“981”
示例 2:
输入:digits = [8,6,7,1,0]
输出:“8760”
示例 3:
输入:digits = [1]
输出:“”
示例 4:
输入:digits = [0,0,0,0,0,0]
输出:“0”
提示:
1 <= digits.length <= 10^4
0 <= digits[i] <= 9
数学方法
class Solution {
public:
string largestMultipleOfThree(vector<int>& digits) {
vector<int> cnt(10), modulo(3);
int sum = 0;
for (int digit: digits) {
++cnt[digit];
++modulo[digit % 3];
sum += digit;
}
int remove_mod = 0, rest = 0;
if (sum % 3 == 1) {
if (modulo[1] >= 1) {
remove_mod = 1;
rest = 1;
}
else {
remove_mod = 2;
rest = 2;
}
}
else if (sum % 3 == 2) {
if (modulo[2] >= 1) {
remove_mod = 2;
rest = 1;
}
else {
remove_mod = 1;
rest = 2;
}
}
string ans;
for (int i = 0; i <= 9; i++) {
for (int j = 0; j < cnt[i]; j++) {
if (rest && remove_mod == i % 3) {
rest--;
}
else {
ans += static_cast<char>(i + 48);
}
}
}
if (ans.size() && ans.back() == '0') {
ans = "0";
}
reverse(ans.begin(), ans.end());
return ans;
}
};
时间复杂度:O(N),其中 N 是数组 digits 的长度。
空间复杂度:O(1),这里统计的是除了返回答案之外的额外空间复杂度。我们需要用到的数组 cnt 的大小为 10,modulo 的大小为 3,可以看作是常数级别。
首先如果每个数字和加起来是3,那么这些数字肯定能被3 整除, 从大到小排序所有数字组成字符串输出即可,如果数字和sum%32 那么去除掉最小的%32的数字,如果没有这类数字,则去除掉两个最小的%31的数字,sum%31 则类似于sum%3==2的思路即可。
以上是这道题的核心思路。我们用两个变量,一个remove_mod来记录sum的余数是什么,是1或者2,rest是要去除元素的数量。
然后ans += static_cast<char>(i + 48);
为什么要加48呢?因为加了48以后就是他的asc2码值,比如说3的asc2码值51是’3’。
还有一个重要的问题是,我们在最后对ans进行reverse操作,那么我们能不能在i从0-9循环,进行从9-0倒序循环,然后不使用reverse操作呢?答案是不可以,因为涉及到我们的remove_mod操作,如果使用倒序,那么会优先删除最大的符合余数条件的字符,而我们要删除的是最小的符合条件的字符,这样才能让ans达到最大。