Given an array of digits digits, return the largest multiple of three that can be formed by concatenating some of the given digits in any order. If there is no answer return an empty string.
Since the answer may not fit in an integer data type, return the answer as a string. Note that the returning answer must not contain unnecessary leading zeros.
Example 1:
Input: digits = [8,1,9]
Output: “981”
Example 2:
Input: digits = [8,6,7,1,0]
Output: “8760”
Example 3:
Input: digits = [1]
Output: “”
Constraints:
- 1 <= digits.length <= 104
- 0 <= digits[i] <= 9
3 的倍数其实说的就是能被 3 整除的数, 一个数能不能被 3 整除, 其实我们是从最高位开始, 把每一位%3 取余数, 即 remain = num[i] % 3, 当到 i + 1 位时, curr_remain = (num[i+1] + remain * 10) % 3。由于%3 的操作的结果无非是 0、1 或者 2, 0 的情况我们不用考虑, 因为它对接下来的求余运算没有影响, 我们来看一下 1 和 2 的情况, 1 在下一步的时候会变成 10(remain*10), 10 % 3 依然是 1, 2 在下一步的时候会变成 20, 20 % 3 还是 2, 也就是说即使我们不把 remain 乘以 10, 对于后续的运算也是没有影响的。 这样我们就可以将每一位的余数进行简单加和, 然后将加和%3 就是这些 digits 组成的任意数字%3 的值。也就是说, 一个 num 能不能被 3 整除只与其中的 digits 的值和数量有关, 与 digits 的相对位置是无关的。到这里问题就简单了, 因为最终余数加%3 也是只有 0、1、2 三种取值, 我们只要根据该值去除掉某些数字即可, 例如余数加和%3 == 1, 那我们只需要移除一个%3 等于 1 的 digit 即可, 这类数字有 1, 4, 7, 由于我们要尽可能的让保留的数字大, 所以我们要尽可能移除小的数字, 但是如果 1, 4, 7 都没有,是不是意味着我们没法生成能被 3 整除的数了呢?也不是, 因为我们还可以通过移除 2 个%3 == 2 的 digit 来解决这一情况, 因为(2 + 2) % 3 == 1。同理, 整体余 2 的情况也可以通过移除 1 个余 2 的 digit 或者 2 个余 1 的 digits 来实现。有的同学可能会问, 如果移除 1 个和移除 2 个的方式都能行得通, 是不是要比较这两种方案的最终答案的大小呢?答案是不用, 因为多一位的 num 永远比少一位的 num 大。这样全部的 digits 我们有了, 又可以计算出要移除那些 digits, 剩余的 digits 倒序排布就是我们要的最终结果了
use std::{cmp::Reverse, collections::BinaryHeap};
impl Solution {
pub fn largest_multiple_of_three(mut digits: Vec<i32>) -> String {
digits.sort();
digits.reverse();
let mut remain_total = 0;
let mut min_digits = vec![BinaryHeap::new(); 3];
let mut digits_counts = vec![0; 10];
for &d in &digits {
remain_total += d % 3;
min_digits[(d % 3) as usize].push(Reverse(d));
digits_counts[d as usize] += 1;
}
remain_total %= 3;
let mut ans = String::new();
match remain_total {
0 => ans = digits.into_iter().map(|v| v.to_string()).collect(),
1 => {
if min_digits[1].is_empty() {
if min_digits[2].len() < 2 {
return "".into();
}
let Reverse(first) = min_digits[2].pop().unwrap();
let Reverse(second) = min_digits[2].pop().unwrap();
digits_counts[first as usize] -= 1;
digits_counts[second as usize] -= 1;
} else {
let Reverse(d) = min_digits[1].pop().unwrap();
digits_counts[d as usize] -= 1;
}
}
_ => {
if min_digits[2].is_empty() {
if min_digits[1].len() < 2 {
return "".into();
}
let Reverse(first) = min_digits[1].pop().unwrap();
let Reverse(second) = min_digits[1].pop().unwrap();
digits_counts[first as usize] -= 1;
digits_counts[second as usize] -= 1;
} else {
let Reverse(d) = min_digits[2].pop().unwrap();
digits_counts[d as usize] -= 1;
}
}
}
if digits_counts.iter().skip(1).all(|v| *v == 0) {
if digits_counts[0] == 0 {
return "".into();
}
return "0".into();
}
let mut ans = String::new();
for (i, v) in digits_counts.into_iter().enumerate().rev() {
if v > 0 {
ans.push_str(&i.to_string().repeat(v as usize));
}
}
ans
}
}