N进制正反累加判回文数(洛谷P1015题题解,Java语言描述)

题目要求

P1015题目链接

在这里插入图片描述

分析

开始的时候写了这么一个代码,应该是比较基础的,是十进制的。

    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();
    }

}

感悟

这个题的代码基本写了半天,充满了各种失败,是很大的挑战。

但这次以后,我想我对利用串和字符处理进制有了很好的认识,这部分内容对我是重要的,以后希望能做得更好。

希望能对大家有所帮助!!
加油!!奥利给!!(晚安啦)

发布了351 篇原创文章 · 获赞 610 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_43896318/article/details/104057368