蓝桥杯基础练习 十六进制转八进制(JAVA)

问题描述

给定n个十六进制正整数,输出它们对应的八进制数。

输入格式
  输入的第一行为一个正整数n (1<=n<=10)。
  接下来n行,每行一个由09、大写字母AF组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过100000。

输出格式
  输出n行,每行为输入对应的八进制正整数。

【注意】
  输入的十六进制数不会有前导0,比如012A。
  输出的八进制数也不能有前导0。

样例输入
  2
  39
  123ABC

样例输出
  71
  4435274

【提示】
  先将十六进制数转换成某进制数,再由某进制数转换成八进制。

解题思路

    首先由题意可知这是一道常见的进制转换算法,器固定的思路就是将十六进制转成另一种进制,然后将另一种进制转成最终要转成的进制。显然此时的关键点在于中间作为中转的进制应该采用哪个。由问题描述可知每个十六进制数长度最长为100000,此时若采用十进制作为中转显然会非常不合适,所以这里我们采用二进制作为中转。接着具体实现思路分两步:
(1)将十六进制数的每一位用四位二进制数表示,然后再将各位的二进制表示拼合再一起,得到该数的二进制表示。
(2)将得到的二进制数,从低位到高位,每三位取一次,将其转为十进制数,最后将得到的各个十进制数按位拼接在一起。

注意:
由于这里十六进制的位数最大可能会达到100000位,所以在这里要格外注意算法的运行效率和对内存的消耗。在这里为了减少不必要的计算量,特将十六进制中的数转成四位二进制数的方法改成了更为简单的映射方法,即将“0-F”的数字通过一个字符串数组{"0000",...,"1111"}对应起来。并在粘结字符串的时候采用StringBuffer来粘结而不采用String的“+”以此来提高算法效率。

算法实现

import java.util.Scanner;

public class Main{
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int counts = input.nextInt();//十六进制数的个数
        String[] arr = new String[counts];
        for (int i = 0; i < counts; i++) {
            arr[i] = input.next();
        }
        for (int i = 0; i < counts; i++) {
            String hexNum = arr[i];
            int index = hexNum.length() / 2;
            hexNum = hextobyte(hexNum.substring(0,index)) + hextobyte(hexNum.substring(index));
            System.out.println(bytetoOct(hexNum));
        }
    }
    //将十六进制转二进制
    public static String hextobyte(String num){
        StringBuffer s = new StringBuffer();
        String[] reverse = {"0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111"};
        for (int i = 0; i < num.length(); i++) {
            char temp = num.charAt(i);
            if(temp == 'A'){
                s.append(reverse[10]);
            }
            if(temp == 'B'){
                s.append(reverse[11]);
            }
            if(temp == 'C'){
                s.append(reverse[12]);
            }
            if(temp == 'D'){
                s.append(reverse[13]);
            }
            if(temp == 'E'){
                s.append(reverse[14]);
            }
            if(temp == 'F'){
                s.append(reverse[15]);
            }
            if(temp-'0' < 10){
                s.append(reverse[temp-'0']);
            }
        }
        return s.toString();
    }
    //通式:十进制数转四位的二进制数(在该程序中为了效率不采用此方法)
    public static String numtobyte(int num){
        String s = "";
        while(num != 0){
            s += num % 2;
            num = num / 2;
        }
        String reverse = new StringBuffer(s).reverse().toString();
        while(reverse.length() < 4){
            reverse = "0" + reverse;
        }
        return reverse;
    }
    //二进制转八进制
    public static String bytetoOct(String s){
        StringBuffer output = new StringBuffer();
        if(s.length() % 3 == 0){
            for (int i = 0; i < s.length(); i= i + 3) {
                String temp = s.substring(i,i+3);
                output.append(bytetonum1(temp));
            }
        }else{
            int first = s.length() % 3;
            output.append(bytetonum1(s.substring(0,first)));
            for (int i = first; i < s.length(); i = i + 3) {
                String temp = s.substring(i,i+3);
                output.append(bytetonum1(temp));
            }
        }
        if(output.charAt(0) == '0'){
            return output.toString().substring(1);
        }
        return output.toString();
    }
    //通式:二进制转十进制(在该程序中为了效率不采用此方法)
    public static int bytetonum(String s){
        int sum = 0;
        int j = 0;
        for (int i = s.length()-1; i >= 0; i--) {
            int num = s.charAt(i) - '0';
            sum += num * Math.pow(2,j);
            j++;
        }
        return sum;
    }
    //简单数字匹配,二进制转十进制
    public static int bytetonum1(String s){
        int num = 0;
        if(s.length() == 3){
            if(s.equals("000")){
                num = 0;
            }
            if(s.equals("001")){
                num = 1;
            }if(s.equals("010")){
                num = 2;
            }if(s.equals("011")){
                num = 3;
            }if(s.equals("100")){
                num = 4;
            }if(s.equals("101")){
                num = 5;
            }if(s.equals("110")){
                num = 6;
            }if(s.equals("111")){
                num = 7;
            }
        }else{
            if(s.equals("0") || s.equals("00")){
                num = 0;
            }
            if(s.equals("1") || s.equals("01")){
                num = 1;
            }
            if(s.equals("10")){
                num = 2;
            }
            if(s.equals("11")){
                num = 3;
            }
        }
        return num;
    }
}

小记

    最初在实现该算法后,在蓝桥杯的练习系统中提交一直出现运行超时的问题,不管我怎么改进还是一直超时。后来去网上找到别人实现的代码,分析了一下,发现我的写的基本思路相同但是,用他的代码提交,即可通过而且我最初提交的代码内存使用是他的进十倍。这就令我很苦恼,然后我又重新对比了一下我们两个的代码,发现我粘结字符串时是通过String的“+”方式粘结的而他则是通过StringBuffer粘结,然后我就在想会不会是这两种字符串拼接的效率有差异,然后查阅网上的博客(点击此处查看)得知,两者的效率确实不同,将我的代码中拼接字符串的方式换成StringBuffer的方式,bingo,我的CPU耗时及内存使用均优于他的程序。

收获

    String字符串拼接“+”与StringBuffer的效率存在差异。在所拼接的数据量大时,StringBuffer的效率要远远高于“+”的方式。原因:当采用String “+”的方式,每循环一次,就会重新new一个StringBuffer对象,这样的内存消耗完全是不必要的,所以建议大家尽量使用StringBuffer或者StringBuilder来进行字符串拼接。

posted @ 2020-03-05 21:21  Alex-jzw  阅读(659)  评论(0)    收藏  举报