描述
现在有一个数组a,你可以从里面取任意个数字,用这些数字组成一个新的数字,例如5,12,3三个数字可以组成新数字5123。
题目需要你求出最大的能被3整除的新组合数字。
- 0< |a| <1000
- 0<= a[i] <=1000 (0<= i < |a|)
- 题目保证数据一定有解
样例1:
输入:[1,2,2]
输出:“21”
样例2:
输入:[1,2,4,6]
输出:"642"
样例3:
输入:[3,0,6,9]
输出:"9630"
解题思路
按照题意的思路去考虑取哪些数,这样情况会比较复杂,解题费时。可以考虑不取哪些数。 可以想到,当数组和模三余0时,必定全取; 当数组和模三余1时,不取一个模三余1的数,或者不取两个模三余2的数; 当数组和模三余2时,不取一个模三余2的数,或者不取两个模三余1的数。
算法流程
- 列表项目计算数组和模三的余数sum,将数组按数值从小到大排序并遍历,第一个模三余数等于sum的数不取,其他数均取
- 将数组内所有值进行排序得到最大值字符串ans_1(自定义排序,比较数字a和b不同顺序连接得到的两个字符串ab和ba大小决定其排序)
- 将数组按数值从小到大遍历,第一个和第二个模三余数等于(3-sum)的数不取,其他数均取,同上得到ans_2
- 若ans_2均存在,返回max(ans_1,ans_2),否则返回ans_1
复杂度分析
- 时间复杂度:O(nmlogn) n为数组长度,m为数组中数字位数,因为排序时复杂度为nlogn,且在其基础上定义了字符串比较大小
- 空间复杂度:O(nm) 需要存下将数组中数组转化为字符串的所有字符
源代码
public class Solution {
/**
* @param a: the array in problem.
* @return: represent the new number.
*/
public String Combine(List<Integer> a) {
int n = a.size();
int flag = 0, sum = 0;
List<String> tmp_1 = new ArrayList<>(), tmp_2 = new ArrayList<>();
String ans_1 = "", ans_2 = "";
Collections.sort(a);
//求数组和模三的余数sum
for (int i = 0; i < n; i++) {
sum += a.get(i);
}
sum %= 3;
for (int i = 0; i < n; i++) {
if(flag == 0 && a.get(i)%3 == sum && sum != 0){
//第一个模三余数等于sum的数不取
flag = 1;
}
else {
tmp_1.add(a.get(i) + "");
}
}
Collections.sort(tmp_1, c);
for(int i = 0; i < tmp_1.size(); i++) {
ans_1 += tmp_1.get(i);
}
flag = 0;
for (int i = 0; i < n; i++) {
if(flag < 2 && a.get(i)%3 == 3 - sum) {
//第一个和第二个模三余数等于3 - sum的数不取
flag++;
}
else {
tmp_2.add(a.get(i) + "");
}
}
if (flag == 2) {
Collections.sort(tmp_2, c);
for(int i = 0; i < tmp_2.size(); i++) {
ans_2 += tmp_2.get(i);
}
if((ans_2.length() > ans_1.length()) || (ans_1.length() == ans_2.length() && ans_2.compareTo(ans_1) > 0))
return ans_2;
}
return ans_1;
}
//自定义排序函数
Comparator<String> c = new Comparator<String>() {
@Override
public int compare(String x, String y) {
String xy = x + y, yx = y + x;
return yx.compareTo(xy);
}
};
}