【蓝桥杯备赛系列 | 简单题】十六进制转八进制、十六进制转十进制、十进制转十六进制 (手撕)
🤵♂️ 个人主页: @计算机魔术师
👨💻 作者简介:CSDN内容合伙人,全栈领域优质创作者。
摘要: 本文旨在准备明年2023的蓝桥杯竞赛,培养个人Java语法素养和手感。 希望可以帮助到一起备赛的小伙伴们。题目来自蓝桥杯刷题网
@[toc]
前言:注意主类是 Main,编辑器用ecilips
一、十六进制转八进制 (进制转换 字符 循环)
资源限制
内存限制:512.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
问题描述
给定n个十六进制正整数,输出它们对应的八进制数。
输入格式
输入的第一行为一个正整数n (1<=n<=10)。
接下来n行,每行一个由0~9、大写字母A~F组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过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();
}
}
显然报错,这里显示数字格式错误,我们点击报错跳转到对应的报错
可以发现这个报错出现在函数parseInt(String s, int radix)
中,调试一番,源码原理是提取十六进制中字符串每个字符单独转换为十进制,result变量初始化为0,依次减去转换得到的十进制,一番循环最终小于限制,及数太大了,超过了定义的值,我们也可以观察到原题中说明十六进制长度大小不超过100000,可以知道调用API会涉及到int来存贮,所以进行操作必须要扩大整形范围或者用字符串转换。
我们将其换为Long型,依旧范围不够,也需要进行读取十六进制,而其中的valueof
函数本质也是调用了 praseint
,范围太大爆掉。
这里尝试使用BigInteger
进行实现,其中通过构造函数,构造对应的进制数,接着调用toString
转换输出
过啦!!!!!!!!!!!!
这里刷了一个小聪明,即用封装好的类调用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
可以避免由于数值太大无法转换的需求,在Integer
的 parseInt
中遇到太大的数值会报错,无法转换
三、十进制转十六进制 (循环 整除 求余 判断)
资源限制
内存限制: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、十六进制和八进制转十进制通过二进制为中间商转换(注意二进制要补零或者判断)。
刷题注意
- 多测试一些输入输出,注意要是一些特殊情况的,有代表性的
- 测试前一定要理一遍代码逻辑对不对,测试并不能测出全部!
- 点赞
- 收藏
- 关注作者
评论(0)