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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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("测试结束");
}
}