蓝桥杯——十六进制转八进制

蓝桥杯——十六进制转八进制

  • 0.前言
  • 1.解题过程
    • 1.1原题
      • 1.1.1问题描述
      • 1.1.2输入格式
      • 1.1.3输出格式
    • 1.2代码
      • 1.2.1常规做法
      • 1.2.2非常规做法(我自己的方法)
        • 1.2.2.1方案概要
        • 1.2.2.2细节问题
        • 1.2.2.3代码
        • 1.2.2.4说明
  • 2.总结

0.前言

这道题乍一看不难,无非就是调用Long.valueOf(n,16);Integer.toString(n, 8),先转成十进制再转成八进制。但仔细看条件会发现数值非常大,这种方法是不行的。

1.解题过程

1.1原题

1.1.1问题描述

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

1.1.2输入格式

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

1.1.3输出格式

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

说明:输入的十六进制数不会有前导0,比如012A,输出的八进制数也不能有前导0。

1.2代码

1.2.1常规做法

思路就是寻找一个能表示很大数值范围的类来表示,BigInteger正好符合

import java.math.BigInteger;
import java.util.Scanner;

public class Main {

	public static void main(String[] agrs) {
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		String[] arr=new String[n];
		String[] brr=new String[n];
		for (int i = 0; i < arr.length; i++) {
			arr[i]=sc.next();
			//调用自带的BigInteger()类表示,需要熟练掌握Java的常用API
			brr[i]=new BigInteger(arr[i],16).toString(8);
		}
		for (int i = 0; i < brr.length; i++) {
			System.out.println(brr[i]);
		}
		sc.close();
	}
}

1.2.2非常规做法(我自己的方法)

最开始我的想法也是找一个能表示的类,但最后没找到,而且看了那么长的字符串之后,感觉就不是让我们直接用,可能是找别的方法。
我的思路是这样,在上课的时候,我们经常把16进制转化为2进制,只需要按位展开,而把2进制转化为16进制只需要每四位转化为16进制拼接即可,那么我就可以把这么长的数字转化为字符串,然后把字符串转化为2进制,再把2进制的字符串每三位为一组转化为8进制的字符串。

1.2.2.1方案概要

确定了思路之后,我们需要考虑几个问题,第一个就是映射的问题,把16进制映射为四位的2进制数字,可以考虑用一个HashMap存储,键为十六进制的0-F,值为二进制的0000-1111。把2进制映射为8进制也是一样的思路,新建一个HashMap,键为二进制的000-111,值为八进制的0-7。遇到key时,直接替换为对应的value。

1.2.2.2细节问题

确定方案之后,还有几个问题需要考虑,第一个就是前导0的问题,如果十六进制下第一位是1,转化为二进制是0001,转化为八进制是001,这样的话,前面两位0不应该存在。需要考虑去除前面多余的0,第二个是,如果二进制的字符串总共有两位,比如11,那么按照建立的HashMap来看就找不到映射,需要考虑这种情况。

1.2.2.3代码

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {

    public static void main(String[] agrs) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        //存储输入的十六进制字符串
        String[] arrStrings = new String[n];
        //遍历赋值
        for (int i = 0; i < n; i++) {
            arrStrings[i] = sc.next();
        }
        //十六进制转二进制的映射表
        Map<String, String> x2bMap = new HashMap<>(16);
        //二进制转八进制的映射表
        Map<String, String> b2oMap = new HashMap<>(8);
        //二进制字符串,StringBuilder做拼接的时候速度比较快
        StringBuilder binaryNumBuilder = new StringBuilder();
        //最终的八进制结果字符串
        StringBuilder resultBuilder = new StringBuilder();
        //键
        String key;
        //值
        String value;
        //局部结果的字符串
        String partString;
        //十六进制转二进制映射表赋值
        for (int i = 0; i < 16; i++) {
            key = String.format("%x", i).toUpperCase();
            value = String.format("%04d", Integer.parseInt(Integer.toBinaryString(i)));
            x2bMap.put(key, value);
        }
        //二进制转八进制映射表赋值
        for (int i = 0; i < 8; i++) {
            key = String.format("%03d", Integer.parseInt(Integer.toBinaryString(i)));
            value = String.valueOf(i);
            b2oMap.put(key, value);
        }
        for (String string : arrStrings) {
            //转化为二进制字符串
            for (int i = 0; i < string.length(); i++) {
                key = String.valueOf(string.charAt(i));
                value = x2bMap.getOrDefault(key, "-1");
                binaryNumBuilder.append(value);
            }
            //考虑如果前面几位为0时候,去除0
            if (binaryNumBuilder.charAt(0)=='0'){
                for (int i = 1; i < 4; i++) {
                    if (binaryNumBuilder.charAt(i) == '1') {
                        binaryNumBuilder = new StringBuilder(binaryNumBuilder.substring(i));
                        break;
                    }
                }
            }
            //二进制转八进制,从后往前,每次-3
            for (int i = binaryNumBuilder.length(); i > 0; i -= 3) {
           		//如果最后字符串长度小于3,需要单独处理
                if (i < 3) {
                    partString = binaryNumBuilder.substring(0, i);
                    partString = String.format("%o", Integer.valueOf(partString, 2));
                } else {
                    partString = binaryNumBuilder.substring(i - 3, i);
                    partString = b2oMap.get(partString);
                }
                resultBuilder.append(partString);
            }
            //此时拼接的字符串是正确结果的倒置,需要倒置后输出
            System.out.println(resultBuilder.reverse().toString());
            //清空,重新赋值
            binaryNumBuilder = new StringBuilder();
            resultBuilder = new StringBuilder();
        }
        sc.close();
    }
}

1.2.2.4说明

代码如上,关键地方都有相应的注释说明,这个方法相对于常规做法复杂了不少,但很锻炼思维。这种模拟计算机进行计算的题目有很多,虽然一个两个可以使用常规做法,但不绝对。掌握这种思想,对之后的练习也有好处。这种方法的时间复杂度和空间复杂度相对于常规做法要小不少,也算是一个成就吧。对比如下。

  • 非常规做法:
    蓝桥杯——十六进制转八进制_第1张图片
  • 常规做法:
    蓝桥杯——十六进制转八进制_第2张图片

2.总结

这道题,我做了很久,后来自己查了一下,发现还有那么简单的常规做法,后来我想明白了基础练习的题目,大多都可以直接做,不需要考虑那么复杂。但考虑复杂,对自己代码能力和思维的严谨性有很大的提高。

你可能感兴趣的:(蓝桥杯,字符串,java,算法,编程语言)