天天看點

藍橋杯——十六進制轉八進制0.前言1.解題過程2.總結

藍橋杯——十六進制轉八進制

  • 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說明

代碼如上,關鍵地方都有相應的注釋說明,這個方法相對于正常做法複雜了不少,但很鍛煉思維。這種模拟計算機進行計算的題目有很多,雖然一個兩個可以使用正常做法,但不絕對。掌握這種思想,對之後的練習也有好處。這種方法的時間複雜度和空間複雜度相對于正常做法要小不少,也算是一個成就吧。對比如下。

  • 非正常做法:
    藍橋杯——十六進制轉八進制0.前言1.解題過程2.總結
  • 正常做法:
    藍橋杯——十六進制轉八進制0.前言1.解題過程2.總結

2.總結

這道題,我做了很久,後來自己查了一下,發現還有那麼簡單的正常做法,後來我想明白了基礎練習的題目,大多都可以直接做,不需要考慮那麼複雜。但考慮複雜,對自己代碼能力和思維的嚴謹性有很大的提高。