题目要求
分析
开始的时候写了这么一个代码,应该是比较基础的,是十进制的。
private static void low() {
Scanner scanner = new Scanner(System.in);
int num = scanner.nextInt();
String str = Integer.toString(num);
int i;
for (i = 0 ; i < 30; i++) {
StringBuilder reverse = new StringBuilder(str).reverse();
//是回文数
if (str.equals(reverse.toString())) {
break;
}
//不是回文数,就增加数值
num += Integer.parseInt(reverse.toString());
str = Integer.toString(num);
}
if (i == 30) {
System.out.println("Impossible!");
} else {
System.out.println("STEP=" + i);
}
scanner.close();
}
但本题是N进制的,数据要求是 2 <= N <= 10 || N == 16 。
要将十六进制和N进制区分开来,分情况讨论。
十六进制的话,在我们使用char的时候,由于大写字母与阿拉伯数字在ASCII里是不连续的,所以我觉得可以建立一个Integer与Character之间的双射关系。
双射关系的“一一对应”不是很容易实现,那就可以建立两个HashMap,一个从Integer到Character,另一个从Character到Integer,利用HashMap的高效性来快速的存取。
读题的话,字符串反转是要做的。
Java不像C,貌似没有直接的reverse(),但可以使用StringBuilder实现:
/**
* 字符串反转
* @param string 待翻转字符串
* @return 翻转后的字符串
*/
private static String reverse(String string) {
return new StringBuilder(string).reverse().toString();
}
还要做回文判定,既然有了reverse,那就直接利用String的equals()即可。二者结合就可以判定是否是回文数啦:
/**
* 判断是否为回文数
* @param num 待判数值
* @return 是否为回文数
*/
private static boolean isPalindrome(String num) {
if (num.equals(reverse(num))) {
return true;
} else {
return false;
}
}
核心是如何操作至多100位的加法呢?(虽然洛谷里本题评测数据没那么变态)
只能是纯粹的利用串和字符进行加法,这也是核心的难点。
下面是十六进制的加法:
/**
* 十六进制加法
* @param num1 加数1
* @param num2 加数2(位数与加数1相同)
* @return 十六进制和
*/
private static String hexAdd(String num1, String num2) {
//获取char[]
char[] chars1 = num1.toCharArray();
char[] chars2 = num2.toCharArray();
//长度
int length = chars1.length;
//结果的char[]
char[] result = new char[length+1];
for (int i = length-1; i >= 0; i--) {
//实际上是int
int temp = charMap.get(chars1[i]) + charMap.get(chars2[i]) + result[i+1];
if (temp >= 16) {
//本位溢出,进位
result[i+1] = intMap.get(temp-16);
result[i]++;
} else {
result[i+1] = intMap.get(temp);
}
}
//最终溢出
if (result[0] == 0) {
return new String(result).substring(1);
}
result[0] += 48;
return new String(result);
}
因为是有A/B/C/D/E/F,但上面也说了原因,这是不好操作的,就利用Map的映射来获取对应的“真值”。
原本想的是先判进位,但是后来发现不行,下面打个比方:
如果先判高位相加时候溢出,是不能满足所有可能的,很多测试数据用上去都会WA掉。
十进制的599+499,明显是会溢出进位的,但5+4不会达到10,如果这就认为不能满足进位,显然就错了。
所以我会开一个长一位的数组,当高位是0的时候(不进位)就利用字符串的取得子串来消去第一位。
进位一定要处理好啊!!!
下面是2~10进制的加法:
/**
* 2-10进制的加法
* @param num1 加数1
* @param num2 加数2(位数与加数1相同)
* @param format 两个数所属进制
* @return N进制和(2 <= N <= 10)
*/
private static String normallyAdd(String num1, String num2, int format) {
//获取char[]
char[] chars1 = num1.toCharArray();
char[] chars2 = num2.toCharArray();
//长度
int length = chars1.length;
//结果的char[]
char[] result = new char[length+1];
for (int i = length-1; i >= 0; i--) {
//实际上是char
int temp = chars1[i] + chars2[i] + result[i+1];
if (temp >= 96 + format) {
//本位溢出,进位
result[i+1] = (char)(temp - format - 48);
result[i]++;
} else {
result[i+1] = (char)(temp - 48);
}
}
//最终溢出
if (result[0] == 0) {
return new String(result).substring(1);
}
result[0] += 48;
return new String(result);
}
这里就可以不用Map啦,其实单纯的操作char就可以啦!!
很多都是类似的,可以看看上面的。
评测数据集Share
我遇到了一些WA和RE问题。
一共有4份测试数据集,我这里有第一个、第二个、第四个。
数据1
in
2
10011
out
STEP=4
数据2
in
16
AC27
out
STEP=6
数据4
in
2
101111
out
Impossible!
AC代码(Java语言描述)
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class Main {
private static Map<Character, Integer> charMap;
private static Map<Integer, Character> intMap;
static {
charMap = new HashMap<>();
charMap.put('0', 0);
charMap.put('1', 1);
charMap.put('2', 2);
charMap.put('3', 3);
charMap.put('4', 4);
charMap.put('5', 5);
charMap.put('6', 6);
charMap.put('7', 7);
charMap.put('8', 8);
charMap.put('9', 9);
charMap.put('A', 10);
charMap.put('B', 11);
charMap.put('C', 12);
charMap.put('D', 13);
charMap.put('E', 14);
charMap.put('F', 15);
intMap = new HashMap<>();
intMap.put(0, '0');
intMap.put(1, '1');
intMap.put(2, '2');
intMap.put(3, '3');
intMap.put(4, '4');
intMap.put(5, '5');
intMap.put(6, '6');
intMap.put(7, '7');
intMap.put(8, '8');
intMap.put(9, '9');
intMap.put(10, 'A');
intMap.put(11, 'B');
intMap.put(12, 'C');
intMap.put(13, 'D');
intMap.put(14, 'E');
intMap.put(15, 'F');
}
/**
* 字符串反转
* @param string 待翻转字符串
* @return 翻转后的字符串
*/
private static String reverse(String string) {
return new StringBuilder(string).reverse().toString();
}
/**
* 十六进制加法
* @param num1 加数1
* @param num2 加数2(位数与加数1相同)
* @return 十六进制和
*/
private static String hexAdd(String num1, String num2) {
//获取char[]
char[] chars1 = num1.toCharArray();
char[] chars2 = num2.toCharArray();
//长度
int length = chars1.length;
//结果的char[]
char[] result = new char[length+1];
for (int i = length-1; i >= 0; i--) {
//实际上是int
int temp = charMap.get(chars1[i]) + charMap.get(chars2[i]) + result[i+1];
if (temp >= 16) {
//本位溢出,进位
result[i+1] = intMap.get(temp-16);
result[i]++;
} else {
result[i+1] = intMap.get(temp);
}
}
//最终溢出
if (result[0] == 0) {
return new String(result).substring(1);
}
result[0] += 48;
return new String(result);
}
/**
* 2-10进制的加法
* @param num1 加数1
* @param num2 加数2(位数与加数1相同)
* @param format 两个数所属进制
* @return N进制和(2 <= N <= 10)
*/
private static String normallyAdd(String num1, String num2, int format) {
//获取char[]
char[] chars1 = num1.toCharArray();
char[] chars2 = num2.toCharArray();
//长度
int length = chars1.length;
//结果的char[]
char[] result = new char[length+1];
for (int i = length-1; i >= 0; i--) {
//实际上是char
int temp = chars1[i] + chars2[i] + result[i+1];
if (temp >= 96 + format) {
//本位溢出,进位
result[i+1] = (char)(temp - format - 48);
result[i]++;
} else {
result[i+1] = (char)(temp - 48);
}
}
//最终溢出
if (result[0] == 0) {
return new String(result).substring(1);
}
result[0] += 48;
return new String(result);
}
/**
* 判断是否为回文数
* @param num 待判数值
* @return 是否为回文数
*/
private static boolean isPalindrome(String num) {
if (num.equals(reverse(num))) {
return true;
} else {
return false;
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
//进制(2-10、16)
int format = Integer.parseInt(scanner.nextLine());
String num = scanner.nextLine();
int counter = 0;
if (format == 16) {
while (!isPalindrome(num) && counter <= 30) {
num = hexAdd(num, reverse(num));
counter++;
}
} else {
while (!isPalindrome(num) && counter <= 30) {
num = normallyAdd(num, reverse(num), format);
counter++;
}
}
if (counter > 30) {
System.out.println("Impossible!");
} else {
System.out.println("STEP=" + counter);
}
scanner.close();
}
}
感悟
这个题的代码基本写了半天,充满了各种失败,是很大的挑战。
但这次以后,我想我对利用串和字符处理进制有了很好的认识,这部分内容对我是重要的,以后希望能做得更好。
希望能对大家有所帮助!!
加油!!奥利给!!(晚安啦)