【蓝桥杯备赛系列 | 简单题】十六进制转八进制、十六进制转十进制、十进制转十六进制 (手撕)

在这里插入图片描述

‍♂️ 个人主页: @计算机魔术师
‍ 作者简介:CSDN内容合伙人,全栈领域优质创作者。

蓝桥杯竞赛专栏 | 简单题系列 (一)
作者: 计算机魔术师
版本: 1.0 ( 2023.3.23 )

摘要: 本文旨在准备明年2023的蓝桥杯竞赛,培养个人Java语法素养和手感。 希望可以帮助到一起备赛的小伙伴们。题目来自蓝桥杯刷题网

文章目录

  • 一、十六进制转八进制 (进制转换 字符 循环)
    • 1.1 BigInteger类 API 实现
    • 1.2 字符串 算法实现
      • 1.2.1 十六进制转二进制
      • 1.2.2 二进制转八进制
  • 二、十六进制转十进制 (进制转换 字符处理 判断)
    • 手撕实现
    • API 实现
  • 三、十进制转十六进制 (循环 整除 求余 判断)
    • 实现
  • 四、总结

前言:注意主类是 Main编辑器用ecilips

一、十六进制转八进制 (进制转换 字符 循环)

资源限制
内存限制:512.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
问题描述
  给定n个十六进制正整数,输出它们对应的八进制数。

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

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

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

样例输入
  2
  39
  123ABC

样例输出
  71
  4435274

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

1.1 BigInteger类 API 实现

面对这个我的问题,我的第一个思路就是调用API哈哈哈。类Integer已经封装了关于进制转换的应用,如下:

十进制转成十六进制: 
Integer.toHexString(int i)  // 注意是int
十进制转成八进制 
Integer.toOctalString(int i) 
十进制转成二进制 
Integer.toBinaryString(int i) 
十六进制转成十进制 
Integer.valueOf("FFFF",16).toString()  // Integer.valueOf(string,radix) 
八进制转成十进制 
Integer.valueOf("876",8).toString() 
二进制转十进制 
Integer.valueOf("0101",2).toString()

以为可以一下解决,初步代码如下:

import java.util.ArrayList;
import java.util.Scanner;
public class Main {
	public static void main(String[] args) {
		Scanner reader = new Scanner(System.in);
		int num = Integer.parseInt(reader.nextLine());
		for(int i = 0;i<num;i++) {
			String get_string = reader.next();
//			String string = Integer.toOctalString(Integer.valueOf(get_string,16));
			String string = Integer.toOctalString((int) Integer.valueOf(get_string,16).longValue());
//			Integer.toOctalString()
			System.out.println(string + "\n");
		}	
	reader.close();
	}
	}

【蓝桥杯备赛系列 | 简单题】十六进制转八进制、十六进制转十进制、十进制转十六进制 (手撕)_第1张图片
显然报错,这里显示数字格式错误,我们点击报错跳转到对应的报错
【蓝桥杯备赛系列 | 简单题】十六进制转八进制、十六进制转十进制、十进制转十六进制 (手撕)_第2张图片
【蓝桥杯备赛系列 | 简单题】十六进制转八进制、十六进制转十进制、十进制转十六进制 (手撕)_第3张图片
【蓝桥杯备赛系列 | 简单题】十六进制转八进制、十六进制转十进制、十进制转十六进制 (手撕)_第4张图片
可以发现这个报错出现在函数parseInt(String s, int radix)中,调试一番,源码原理是提取十六进制中字符串每个字符单独转换为十进制,result变量初始化为0,依次减去转换得到的十进制,一番循环最终小于限制,及数太大了,超过了定义的值,我们也可以观察到原题中说明十六进制长度大小不超过100000,可以知道调用API会涉及到int来存贮,所以进行操作必须要扩大整形范围或者用字符串转换

我们将其换为Long型,依旧范围不够,也需要进行读取十六进制,而其中的valueof函数本质也是调用了 praseint ,范围太大爆掉。
【蓝桥杯备赛系列 | 简单题】十六进制转八进制、十六进制转十进制、十进制转十六进制 (手撕)_第5张图片

这里尝试使用 BigInteger 进行实现,其中通过构造函数,构造对应的进制数,接着调用toString转换输出

【蓝桥杯备赛系列 | 简单题】十六进制转八进制、十六进制转十进制、十进制转十六进制 (手撕)_第6张图片

在这里插入图片描述

过啦!!!!!!!!!!!!
这里刷了一个小聪明,即用封装好的类调用API实现,实际上没有用到算法。为了刷题的本心,我们对应题目所需要求(进制转换 字符 循环),按照字符串来做(我觉得实现结果和BigInteger的构造函数可以参考)

1.2 字符串 算法实现

首先我们先观察十六进制和八进制、二进制。 (表格是手敲的,可以给一个三连吗)

十六进制 八进制 二进制(对十六机制) 二进制(对八机制) 十进制
0 0 0000 000 0
1 1 0001 001 1
2 2 0010 010 2
3 3 0011 011 3
4 4 0100 100 4
5 5 0101 101 5
6 6 0110 110 6
7 7 0111 111 7
8 10 1000 001 000 8
9 11 1001 001 001 9
A 12 1010 001 010 10
B 13 1011 001 011 11
C 14 1100 001 100 12
D 15 1101 001 101 13
E 16 1110 001 110 14
F 17 1111 001 111 15
10 20 0001 0000 010 000 16

从表格中可以明显看到十六进制与八进制与二进制的对应关系。

其中十六进制每一个位对应 一个四位的二进制
每个八进制一个位对应 一个三位的二进制

那我们在这里的思想便是使用字符串对应

1.2.1 十六进制转二进制

public static String HexToBinary(String get_string) {
		String results = "";
		for(int j=0;j<get_string.length();j++) {
//			System.out.println(get_string.charAt(j));
			switch(get_string.charAt(j)) {
			case '0':results += "0000";break;
			case '1':results += "0001";break;
			case '2':results += "0010";break;
			case '3':results += "0011";break;
			case '4':results += "0100";break;
			case '5':results += "0101";break;
			case '6':results += "0110";break;
			case '7':results += "0111";break;
			case '8':results += "1000";break;
			case '9':results += "1001";break;
			case 'A':results += "1010";break;
			case 'B':results += "1011";break;
			case 'C':results += "1100";break;
			case 'D':results += "1101";break;
			case 'E':results += "1110";break;
			case 'F':results += "1111";break;
			}
		}
		return results;
	}

1.2.2 二进制转八进制

注意要先去掉字符串前面的0(避免生成的八进制前面有0),接着如果字符串长度不够为3的倍数,要补零

public static String BinaryToOct(String get_string) {
		String results = "";
		int index=0;
//		System.out.print(get_string.charAt(index));
		while(get_string.charAt(index) == '0') {
			get_string = get_string.substring(1);
		}
		
		while(get_string.length()%3 != 0) {
			get_string = "0" +  get_string;
		}	
//		System.out.println("补零" + get_string);
		for(int j=0;j<get_string.length();j+=3) {
			char temp[] = new char[3];
			get_string.getChars(j, j+3,temp, 0);
			String string = String.copyValueOf(temp);
			switch(string) {
			case "000":results += "0";break;
			case "001":results += "1";break;
			case "010":results += "2";break;
			case "011":results += "3";break;
			case "100":results += "4";break;
			case "101":results += "5";break;
			case "110":results += "6";break;
			case "111":results += "7";break;
			}
		}
		return results;
	}

此时我们提交代码。超时啦!! 可以看到运行内存很大
在这里插入图片描述
所以尝试在换成八进制的代码,不再用直接替换,我们将 BinaryToOct 函数改成如下代码

public static String BinaryToOct(String get_string) {
		String results = "";
		int index=0;
//		System.out.print(get_string.charAt(index));
		while(get_string.charAt(index) == '0') {
			get_string = get_string.substring(1); // 去零
		}
		while(get_string.length()%3 != 0) {  // 加零
			get_string = "0" +  get_string;
		}	
//		System.out.println("补零" + get_string);
		for(int j=0;j<get_string.length();j+=3) {
			String temp = get_string.substring(j, j+3);
			// 因为这里的对应关系 三对一,实际便是二进制转十进制的关系
			// 注意不要用默认类型转换,这里的自动转换会把char(即便是string,里面也是多个char组成)转换成对应ASCII码!
//			int b = (int)(temp.charAt(0) - '0');
//			int c =temp.charAt(0) - '0'; // 注意
			int aa =  (int)(temp.charAt(0) - '0') * 4 + (int)(temp.charAt(1) - '0') * 2 + (int)(temp.charAt(2) - '0'); 
			results +=String.valueOf(aa);
		}
		return results;
	}

注意一下关于 char自动转换的问题,char - 0**会自动把 char的字符转换成ascii码!!**会导致数值错误,需要 char - '0'才能实现数值不变

在Java中,字符(char)类型实际上是整数(int)类型的小范围表示,也就是说,每个字符都有一个对应的整数ASCII码值,而这个值可以通过强制类型转换将字符转换成整数。字符’0’到’9’的ASCII码值依次为48到57。

因此,当我们将一个字符类型的数字减去字符’0’时,实际上是将该字符的ASCII码值减去字符’0’的ASCII码值(即48),从而得到这个数字的整数值

以下是一个简单的示例代码,它演示了如何将字符类型的数字转换为整数类型:

char c = '5';
int num = c - '0';
System.out.println(num); // 输出结果为 5

在这个示例代码中,字符’5’的ASCII码值为53,字符’0’的ASCII码值为48,因此执行c - '0’的操作,实际上等价于53 - 48,最终得到的整数值为5。
在这里插入图片描述
内存还是爆了‍♂️,还是改改算法 (减少空间复杂度)。

我们整理一下思路,我们转换成二进制,在转换到八进制,其中用的是String,注意到String是不可变的,每次更新都会产生新的String , 我们改用成StringBuffer,再用回之前的直接替换,减去逻辑操作.

import java.math.BigInteger;
import java.io.IOException;
import java.util.Scanner;
public class Main {
	public static void main(String[] args) throws NumberFormatException, IOException {
		Scanner reader = new Scanner(System.in);
		int num = Integer.parseInt(reader.nextLine());
		for(int i = 0;i<num;i++) {
			StringBuffer results_oct = new StringBuffer();
			StringBuffer get_string = new StringBuffer(reader.next()); // 
			results_oct = BinaryToOct(HexToBinary(get_string));
			System.out.println(results_oct.toString());
		}	
	reader.close();
	}
	public static StringBuffer HexToBinary(StringBuffer get_string) {
		StringBuffer results = new StringBuffer("");
		for(int j=0;j<get_string.length();j++) {
			switch(get_string.charAt(j)) {
			case '0':results.append("0000");break;
			case '1':results.append("0001");break;
			case '2':results.append("0010");break;
			case '3':results.append("0011");break;
			case '4':results.append("0100");break;
			case '5':results.append("0101");break;
			case '6':results.append("0110");break;
			case '7':results.append("0111");break;
			case '8':results.append("1000");break;
			case '9':results.append("1001");break;
			case 'A':results.append("1010");break;
			case 'a':results.append("1010");break;
			case 'B':results.append("1011");break;
			case 'b':results.append("1011");break;
			case 'C':results.append("1100");break;
			case 'c':results.append("1100");break;
			case 'D':results.append("1101");break;
			case 'd':results.append("1101");break;
			case 'E':results.append("1110");break;
			case 'e':results.append("1110");break;
			case 'F':results.append("1111");break;
			case 'f':results.append("1111");break;
			}
		}
		return results;
	}
	public static StringBuffer BinaryToOct(StringBuffer get_string) {
		StringBuffer results = new StringBuffer("");
		int index=0;
		while(get_string.charAt(index) == '0') {
			get_string = new StringBuffer(get_string.substring(1)); // 去零
		}
		
		while(get_string.length()%3 != 0) {  // 加零
			get_string = new StringBuffer("0").append(get_string);
		}	
		for(int j=0;j<get_string.length();j+=3) {
			String temp = get_string.substring(j, j+3);
			String string = String.valueOf(temp);
			switch(string) {
			case "000":results.append("0");break;
			case "001":results.append("1");break;
			case "010":results.append("2");break;
			case "011":results.append("3");break;
			case "100":results.append("4");break;
			case "101":results.append("5");break;
			case "110":results.append("6");break;
			case "111":results.append("7");break;
			}  
		}
		return results;
	}
}

在这里插入图片描述
过啦 !!!!!!!!

二、十六进制转十进制 (进制转换 字符处理 判断)

资源限制
内存限制:512.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s

问题描述
  从键盘输入一个不超过8位的正的十六进制数字符串,将它转换为正的十进制数后输出。
  注:十六进制数中的10~15分别用大写的英文字母A、B、C、D、E、F表示。

样例输入
FFFF

样例输出
65535

手撕实现

题目中说到不超过8位,显然对数据大小存储要求不是特别高,这里我们要用long存贮整形尝试一下。尝试最大的数FFFFFFFF,可以跑出来,那就没有问题了。

package theBuleCup;
import java.math.BigInteger;
import java.util.Scanner;
//import java.io.S;
public class 十六进制转十进制 {
	public static void main(String args[]) {
		Scanner reader = new Scanner(System.in);
		String get_string = reader.next();
		long results = 0;
		for(int i=0;i<get_string.length();i++) {
			int multipler = 0;
			char single_char = get_string.charAt(i);
			switch(single_char) {
				case '0': multipler = 0;break;
				case '1': multipler = 1;break;
				case '2': multipler = 2;break;
				case '3': multipler = 3;break;
				case '4': multipler = 4;break;
				case '5': multipler = 5;break;
				case '6': multipler = 6;break;
				case '7': multipler = 7;break;
				case '8': multipler = 8;break;
				case '9': multipler = 9;break;
				case 'A': multipler = 10;break;
				case 'B': multipler = 11;break;
				case 'C': multipler = 12;break;
				case 'D': multipler = 13;break;
				case 'E': multipler = 14;break;
				case 'F': multipler = 15;break;
		}
			results += multipler *(Math.pow(16, get_string.length()-i - 1));
		}
		System.out.print(results);
		reader.close();
	}
}

在这里插入图片描述
对啦!!!

其实博主在刷这个题。因为java基础不是特别扎实的缘故,会在一些很小的地方犯错,所以建议一定要多测试数据!!才能更好的即使发现错误,还有就是写完要把整体代码逻辑顺一遍!

API 实现

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

public class 十六进制转十进制 {
	public static void main(String args[]) {
		Scanner reader = new Scanner(System.in);
		String get_string = reader.next();
		long results = 0;
		BigInteger hex =  new BigInteger(get_string,16);
		System.out.print(hex.toString(10));
		reader.close();
	}
}

在这里插入图片描述
对啦!!!!!!

可以看到用API实现,他人已经实现,且不会出错,这样快速编写代码,在比赛中非常快速! 但是在平时还是建议大家练练手撕、

tips: 这里使用 BigInteger 可以避免由于数值太大无法转换的需求,在IntegerparseInt 中遇到太大的数值会报错,无法转换

三、十进制转十六进制 (循环 整除 求余 判断)

资源限制
内存限制:512.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s

问题描述
  十六进制数是在程序设计时经常要使用到的一种整数的表示方式。它有0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F共16个符号,分别表示十进制数的0至15。十六进制的计数方法是满16进1,所以十进制数16在十六进制中是10,而十进制的17在十六进制中是11,以此类推,十进制的30在十六进制中是1E。
  给出一个非负整数,将它表示成十六进制的形式。
  
输入格式
  输入包含一个非负整数a,表示要转换的数。0<=a<=2147483647
  
输出格式
  输出这个整数的16进制表示
  
样例输入
30

样例输出
1E

实现

我们可以看到a 的范围恰好就是 long 的整数范围,所以提醒我们用 long 来存贮,代码如下:

package theBuleCup;
import java.util.Scanner;

public class Main {
	public static void main(String args[]) {
		Scanner read  = new Scanner(System.in);
		long get = read.nextLong();
		long get_temp = get;
		String results = "";
		long divisor ;
		long remainder ;
		do {
			divisor = (long) (get / 16);  //获取除数
			remainder = (long) (get % 16); // 获取余数
			results = getHexAtSingle(remainder) + results;  // 对余数进行字符串相加到末尾
			get = divisor;
		}while(divisor>=16); // 判断是否可以再次相除
		if(get_temp >= 16) // 大于等于16才有可能余数前缀有效
			results = getHexAtSingle(divisor) + results;  // 添加到头
		System.out.print(results);
		read.close(); 
	}
	public static String getHexAtSingle(Long remainder) {
		String temp = "";
		switch(String.valueOf(remainder)) {
		case "0": temp = "0";break;
		case "1": temp = "1";break;
		case "2": temp = "2";break;
		case "3": temp = "3";break;
		case "4": temp = "4";break;
		case "5": temp = "5";break;
		case "6": temp = "6";break;
		case "7": temp = "7";break;
		case "8": temp = "8";break;
		case "9": temp = "9";break;
		case "10": temp = "A";break;
		case "11": temp = "B";break;
		case "12": temp = "C";break;
		case "13": temp = "D";break;
		case "14": temp = "E";break;
		case "15": temp = "F";break;
//		case "16": temp = "F";break;
		};
		return temp;
	}
}

在这里插入图片描述
过啦 !!!

关于API的方法这里就不赘述啦,看了前面的内容大家应该都知道怎么解决了。

四、总结

进制转换方法:
1、二进制转八进制——取每三位按权相加。
2、二进制转十六进制—取每四位按权相加。
3、二进制转十进制——按权相加。
4、八进制转二进制——转换字符串
6、十六进制转二进制—同八进制,注意不足四位补0,去前导0.
7、十进制转八进制——除八取余。
8、十进制转十六进制—除十六取余。
9、十六进制和八进制转十进制通过二进制为中间商转换(注意二进制要补零或者判断)。

刷题注意

  1. 多测试一些输入输出,注意要是一些特殊情况的,有代表性的
  2. 测试前一定要理一遍代码逻辑对不对,测试并不能测出全部!

你可能感兴趣的:(刷题之路,蓝桥杯备赛系列,Java,精通进阶之路,蓝桥杯,java,职场和发展,算法)