zoukankan      html  css  js  c++  java
  • 蓝桥杯 16进制转换8进制

    蓝桥杯 16进制转换8进制

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

    题目

    问题描述
      给定n个十六进制正整数,输出它们对应的八进制数。
    输入格式
      输入的第一行为一个正整数n (1<=n<=10)。
      接下来n行,每行一个由0~9、大写字母A~F组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过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进制

      扩展知识

    4. [JAVA]二进制,八进制,十六进制,十进制间进行相互转换,使用类Integer进行进制之间的转换。
    5. Sprintf equivalent in Java需求为,C代码为
      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 );
  • 相关阅读:
    python 的基础 学习 第六天 基础数据类型的操作方法 字典
    python 的基础 学习 第五天 基础数据类型的操作方法
    python 的基础 学习 第四天 基础数据类型
    ASP.NET MVC 入门8、ModelState与数据验证
    ASP.NET MVC 入门7、Hellper与数据的提交与绑定
    ASP.NET MVC 入门6、TempData
    ASP.NET MVC 入门5、View与ViewData
    ASP.NET MVC 入门4、Controller与Action
    ASP.NET MVC 入门3、Routing
    ASP.NET MVC 入门2、项目的目录结构与核心的DLL
  • 原文地址:https://www.cnblogs.com/zhjsll/p/4330323.html
Copyright © 2011-2022 走看看