在这里插入图片描述

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

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

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

前言:注意主类是 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();
	}
	}

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

我们将其换为Long型,依旧范围不够,也需要进行读取十六进制,而其中的valueof函数本质也是调用了 praseint ,范围太大爆掉。
在这里插入图片描述

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

在这里插入图片描述

在这里插入图片描述

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

1.2 字符串 算法实现

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

十六进制八进制二进制(对十六机制)二进制(对八机制)十进制
0000000000
1100010011
2200100102
3300110113
4401001004
5501011015
6601101106
7701111117
8101000001 0008
9111001001 0019
A121010001 01010
B131011001 01111
C141100001 10012
D151101001 10113
E161110001 11014
F171111001 11115
10200001 0000010 00016

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

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

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

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、十六进制和八进制转十进制通过二进制为中间商转换(注意二进制要补零或者判断)。

刷题注意

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

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐