美文网首页
蓝桥杯 16进制转换8进制

蓝桥杯 16进制转换8进制

作者: 肉团先生 | 来源:发表于2015-01-23 21:45 被阅读8110次

    蓝桥杯 16进制转换8进制

    我表示我自己太渣渣了,总是超时,通不过测试。

    题目

    问题描述
      给定n个十六进制正整数,输出它们对应的八进制数。
    输入格式
      输入的第一行为一个正整数n (1<=n<=10)。
      接下来n行,每行一个由09、大写字母AF组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过100000。
    输出格式
      输出n行,每行为输入对应的八进制正整数。
    注意
      输入的十六进制数不会有前导0,比如012A。
      输出的八进制数也不能有前导0。
    样例输入
    2
    39
    123ABC
    样例输出
    71
    4435274
    提示
      先将十六进制数转换成某进制数,再由某进制数转换成八进制。

    思路

    刚开始没有什么思路,就用最原始的做法,先将16进制转换为10进制,然后再由10进制转换为8进制,结果错误。下载测试的数据,才发现数据时如此变态,变换成BigInteger来存储数据,结果运行超时,思考后,发现按照传统的方式,是无法通过的,迫不得已上网找答案,找进制转换的技巧。

    进制转换基础,进制转换可知,可以将16进制转换为2进制,再由2进制进行转化8进制,至于为什么这样做呢,因为16进制每一个位子上的数字都可以变成4位的2进制数,而每3个二进制数又可以组成8进制上对应位子的数字

    再通过数电逻辑上计算2进制的方法:8421法,对应有1的位置加上对应的数字,结果应该就可以出来了。而我按照思路编写之后,还是运行超时。到底哪里出错,看到参考通过的例子后,我才发现,自己的算法确实不够优化

    测试数据

    变态的测试数据

    16转10,10转8

    /*
         * 这种是16进制转化成10进制,然后再转化成8进制 超时,
         */
        public void convert16from10to8(String num16) {
            int flag = 0;
            BigInteger sum = new BigInteger("0");
            BigInteger tmp = new BigInteger("16");
            // 16先转换成10进制
            char[] chArr = num16.toCharArray();
            for (int x = chArr.length - 1; x >= 0; x--) {
                switch (chArr[x]) {
                case 'A':
                case 'B':
                case 'C':
                case 'D':
                case 'E':
                case 'F':
                    // sum += (chArr[x] - '0'-7) * Math.pow(16, flag++);
                    sum = sum.add(tmp.pow(flag++).multiply(
                            new BigInteger((chArr[x] - '0' - 7) + "")));
                    break;
                default:
                    // sum += (chArr[x] - '0') * Math.pow(16, flag++);
                    sum = sum.add(tmp.pow(flag++).multiply(
                            new BigInteger((chArr[x] - '0') + "")));
                    break;
                }
            }
            System.out.println(sum);
            StringBuffer sb = new StringBuffer();
            while (sum.intValue() > 8) {
                // sb.append(sum%8);
                sb.insert(0, sum.remainder(new BigInteger("8")));
                sum = sum.divide(new BigInteger("8"));
            }
            sb.insert(0, sum);
            // sb.append(sum);
            System.out.println(sb.toString());
        }
    
    

    16转2,2转8

        /*
         * 16进制转成2进制,再转8进制 16--》2 每个位上的数字都可以转化为4个位的2进制
         * 每三个为上的2进制组合转化为8进制上的每个位上的数字,不够就补0
         */
        public void convert16from2to8(String num16) {
            char[] chArr = num16.toCharArray();
            int tmp = 0;
            StringBuffer sbSum = new StringBuffer();
            for (int x = 0; x < chArr.length; x++) {
                switch (chArr[x]) {// 字符对应的整数
                case 'A':
                case 'B':
                case 'C':
                case 'D':
                case 'E':
                case 'F':
                    tmp = chArr[x] - '0' - 7;
                    break;
                default:
                    tmp = chArr[x] - '0';
                    break;
    
                }
                StringBuffer sb = new StringBuffer();
                // 转化为二进制
                while (tmp >= 2) {
                    sb.insert(0, tmp % 2);
                    tmp /= 2;
                }
                sb.insert(0, tmp);
                // System.out.println(sb.length());
                int len = 4 - sb.length();// 假如直接写在for循环里面sb在变化,导致len会变化
                for (int y = 0; y < len; y++)
                    sb.insert(0, 0);
                // System.out.println(sb.toString());
                sbSum.append(sb);
            }
            
    //      System.out.println(sbSum.toString());
            StringBuffer sbSum8=new StringBuffer();//记录最终的结果
            int tmp8item=0;
            // 每3个一组,不够尽兴高位补0,即最左边补0,采用421,
            // 或者用一个3做循环,进行划分区域,有1,就根据421的方式进行相加
            char[] chArr2 = sbSum.toString().toCharArray();
            //1001
            for (int z = chArr2.length - 1, num3 = 0; z >= 0; z--) {
                if (chArr2[z] - '0' == 1) {
                    switch (num3) {
                    case 0:
                        tmp8item+=1;
                        break;
                    case 1:
                        tmp8item+=2;
                        break;
                    case 2:
                        tmp8item+=4;
                        break;
                    }
                }
                if((num3+1)%3==0){
                    sbSum8.insert(0, tmp8item);
                    tmp8item=0;
                }
                num3=(num3+1)%3;
            }
            if(sbSum8.substring(0, 1).equals("0"))//输出的八进制数也不能有前导0的判断
                System.out.println(sbSum8.substring(1,sbSum8.length()));
            else
                System.out.println(sbSum8.toString());
        }
    
    

    别人的思路

    1. 1位16进制可以代表4位2进制, 1位8进制可以代表3位二进制,得出3位16进制求和入栈输出表示4位8进制,然后出栈输出。

    2. 我的理解为:
      3位16进制,一位16进制可用4位2进制表示,即:34=12。
      4位8进制,一位8进制可用3位2进制表示,即:4
      3-12
      所以,他们俩之间进行等价

    3. 完整代码(可通过测试):

    import java.util.Scanner;
    public class Main {
        public static void main(String[] args) {
            new Main().systemScanner();
        }
        public void systemScanner() {
            Scanner jin = new Scanner(System.in);
            while (jin.hasNext()) {
                int length = jin.nextInt();
                for (int i = 0; i < length; i++){
                    String strTmp=jin.next();
                    tranform(strTmp.toCharArray(), strTmp.length());
                }
            }
        }
        /*
         * 3位16进制等价于4位8进制
         */
        int[] stack=new int[40000];
        public void tranform(char[] str, int length) {
            char[] buff = new char[4];
            int top = -1;
            for (int i = length - 1; i >= 0; i -= 3) {
                int sum = 0;
                for (int j = 0; j < 3 && i - j >= 0; j++) {// i-j>=0防止不够三个的情况
                    int tmp = str[i - j] >= '0' && str[i - j] <= '9' ? str[i - j] - '0'
                            : str[i - j] - 'A' + 10;//区分是数字,还是字符,进行对应转换
                    sum+=(tmp<<(4*j));//这句很重要,通过这句就可以从16变成10进制了,不过,不知道为什么?是如何得出的呢?而且进行累加之后就能得到最终的结果很神奇
                }
                stack[++top]=sum;//sum的结果是16进制转化10进制的结果,每3个16进制变成10进制,再变8进制
            }
            while(stack[top]==0){//排除前导为0的判断
                top--;
            }
    //      for(int i=top;i>=0;i--){//直接输出会丢失前导0,因为此转化成8进制并不是最左边的情况,应该保留0
    //          System.out.print(Integer.toOctalString(stack[i]));//从10进制转化成8进制
    //      }
            for(int i=top;i>=0;i--){
                String str1=Integer.toOctalString(stack[i]);//从10进制转化成8进制
                if(i!=top&&str1.length()<4){
                    //不是最左边的一个,就不用去掉前导0,而默认是去掉0的,所以要进行补会
                    for(int y=0;y<4-str1.length();y++)
                        System.out.print("0");
                }
                System.out.print(str1);
            }
            System.out.println();
    
        }
    }
    

    参考通过的例子

    【蓝桥杯】16转换8进制

    扩展知识

    char buff[4];
    sprintf(buff ,"%o", stack[i]);
    

    相对应的java代码为

    // Store the formatted string in 'result'
    String result = String.format("%4d", i * j);
    // Write the result to standard output
    System.out.println( result );
    

    相关文章

      网友评论

          本文标题:蓝桥杯 16进制转换8进制

          本文链接:https://www.haomeiwen.com/subject/slzhxttx.html