You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
6.6 KiB

2 years ago
package class40;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.TreeSet;
// 来自去哪儿网
// 给定一个arr里面的数字都是0~9
// 你可以随意使用arr中的数字哪怕打乱顺序也行
// 请拼出一个能被3整除的最大的数字用str形式返回
public class Code02_Mod3Max {
public static String max1(int[] arr) {
Arrays.sort(arr);
for (int l = 0, r = arr.length - 1; l < r; l++, r--) {
int tmp = arr[l];
arr[l] = arr[r];
arr[r] = tmp;
}
StringBuilder builder = new StringBuilder();
TreeSet<String> set = new TreeSet<>((a, b) -> Integer.valueOf(b).compareTo(Integer.valueOf(a)));
process1(arr, 0, builder, set);
return set.isEmpty() ? "" : set.first();
}
public static void process1(int[] arr, int index, StringBuilder builder, TreeSet<String> set) {
if (index == arr.length) {
if (builder.length() != 0 && Integer.valueOf(builder.toString()) % 3 == 0) {
set.add(builder.toString());
}
} else {
process1(arr, index + 1, builder, set);
builder.append(arr[index]);
process1(arr, index + 1, builder, set);
builder.deleteCharAt(builder.length() - 1);
}
}
public static String max2(int[] arr) {
if (arr == null || arr.length == 0) {
return "";
}
Arrays.sort(arr);
for (int l = 0, r = arr.length - 1; l < r; l++, r--) {
int tmp = arr[l];
arr[l] = arr[r];
arr[r] = tmp;
}
if (arr[0] == 0) {
return "0";
}
String ans = process2(arr, 0, 0);
String res = ans.replaceAll("^(0+)", "");
if (!res.equals("")) {
return res;
}
return ans.equals("") ? ans : "0";
}
// arr中的数字一定是0~9
// arr是经过排序的并且是从大到小排序比如[9,8,7,7,7,3,1]等
// 这个递归函数的含义 :
// 在arr[index...一直到最后]上做选择arr[0...index-1]就当不存在
// 每个位置的字符可以要、也可以不要,但是!选出来的数字拼完之后的结果,在%3之后余数一定要是mod
// 返回在上面设定的情况下,最大的数是多少?
// 如果存在这样的数,返回字符串的形式
// 如果不存在这样的数,返回特殊字符串,比如"$",代表不可能
// 这个递归函数可以很轻易的改出动态规划
public static String process2(int[] arr, int index, int mod) {
if (index == arr.length) {
return mod == 0 ? "" : "$";
}
String p1 = "$";
int nextMod = nextMod(mod, arr[index] % 3);
String next = process2(arr, index + 1, nextMod);
if (!next.equals("$")) {
p1 = String.valueOf(arr[index]) + next;
}
String p2 = process2(arr, index + 1, mod);
if (p1.equals("$") && p2.equals("$")) {
return "$";
}
if (!p1.equals("$") && !p2.equals("$")) {
return smaller(p1, p2) ? p2 : p1;
}
return p1.equals("$") ? p2 : p1;
}
public static int nextMod(int require, int current) {
if (require == 0) {
if (current == 0) {
return 0;
} else if (current == 1) {
return 2;
} else {
return 1;
}
} else if (require == 1) {
if (current == 0) {
return 1;
} else if (current == 1) {
return 0;
} else {
return 2;
}
} else { // require == 2
if (current == 0) {
return 2;
} else if (current == 1) {
return 1;
} else {
return 0;
}
}
}
public static boolean smaller(String p1, String p2) {
if (p1.length() != p2.length()) {
return p1.length() < p2.length();
}
return p1.compareTo(p2) < 0;
}
// 贪心的思路解法 :
// 先得到数组的累加和记为sum
// 1) 如果sum%3==0说明所有数从大到小拼起来就可以了
// 2) 如果sum%3==1说明多了一个余数1
// 只需要删掉一个最小的数(该数是%3==1的数);
// 如果没有,只需要删掉两个最小的数(这两个数都是%3==2的数);
// 3) 如果sum%3==2说明多了一个余数2
// 只需要删掉一个最小的数(该数是%3==2的数);
// 如果没有,只需要删掉两个最小的数(这两个数都是%3==1的数);
// 如果上面都做不到,说明拼不成
public static String max3(int[] A) {
if (A == null || A.length == 0) {
return "";
}
int mod = 0;
ArrayList<Integer> arr = new ArrayList<>();
for (int num : A) {
arr.add(num);
mod += num;
mod %= 3;
}
if ((mod == 1 || mod == 2) && !remove(arr, mod, 3 - mod)) {
return "";
}
if (arr.isEmpty()) {
return "";
}
arr.sort((a, b) -> b - a);
if (arr.get(0) == 0) {
return "0";
}
StringBuilder builder = new StringBuilder();
for (int num : arr) {
builder.append(num);
}
return builder.toString();
}
// 在arr中要么删掉最小的一个、且%3之后余数是first的数
// 如果做不到,删掉最小的两个、且%3之后余数是second的数
// 如果能做到返回true不能做到返回false
public static boolean remove(ArrayList<Integer> arr, int first, int second) {
if (arr.size() == 0) {
return false;
}
arr.sort((a, b) -> compare(a, b, first, second));
int size = arr.size();
if (arr.get(size - 1) % 3 == first) {
arr.remove(size - 1);
return true;
} else if (size > 1 && arr.get(size - 1) % 3 == second && arr.get(size - 2) % 3 == second) {
arr.remove(size - 1);
arr.remove(size - 2);
return true;
} else {
return false;
}
}
// a和b比较:
// 如果余数一样,谁大谁放前面
// 如果余数不一样余数是0的放最前面、余数是s的放中间、余数是f的放最后
public static int compare(int a, int b, int f, int s) {
int ma = a % 3;
int mb = b % 3;
if (ma == mb) {
return b - a;
} else {
if (ma == 0 || mb == 0) {
return ma == 0 ? -1 : 1;
} else {
return ma == s ? -1 : 1;
}
}
}
// 为了测试
public static int[] randomArray(int len) {
int[] arr = new int[len];
for (int i = 0; i < len; i++) {
arr[i] = (int) (Math.random() * 10);
}
return arr;
}
// 为了测试
public static int[] copyArray(int[] arr) {
int[] ans = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
ans[i] = arr[i];
}
return ans;
}
// 为了测试
public static void main(String[] args) {
int N = 10;
int testTimes = 10000;
System.out.println("测试开始");
for (int i = 0; i < testTimes; i++) {
int len = (int) (Math.random() * N);
int[] arr1 = randomArray(len);
int[] arr2 = copyArray(arr1);
int[] arr3 = copyArray(arr1);
String ans1 = max1(arr1);
String ans2 = max2(arr2);
String ans3 = max3(arr3);
if (!ans1.equals(ans2) || !ans1.equals(ans3)) {
System.out.println("出错了!");
for (int num : arr3) {
System.out.print(num + " ");
}
System.out.println();
System.out.println(ans1);
System.out.println(ans2);
System.out.println(ans3);
break;
}
}
System.out.println("测试结束");
}
}