蓝桥杯-十六进制转八进制(Java)
最近在练习算法题,打算应付一下下学期的蓝桥杯,写写博客记录一下我的学习过程,对算法感兴趣的朋友可以给小编点点关注
(重要的事情加上强调标志,o( ̄︶ ̄)o),这个假期,我会尽量多的把我遇到的有质量的算法题以博客的形式呈现给大家,算法题的难度也会是有难到易的增长的,希望在这个假期里我们能够共同进步,大家一起努力o( ̄︶ ̄)o
那废话也不多说了,咋们开始步入正题
先把这道题目展现给大家
我想再次写下我整个思考的过程,所以写的比较多,有的代码只是尝试的过程,有一些小问题(在讲解的过程中我也会说明原因的o( ̄︶ ̄)o),无法通过蓝桥杯的编译,如果着急想看解决方法的小伙伴可以直接看尝试三,这个代码可以直接通过编译。
第一次尝试:
其实就是把一个十六进制数转化成八进制,其实对于这道题我一开始思考的是相对比较常规的写法:把十六进制转化成十进制再将十进制转化成八进制。 这个是我当时用这种方法写的代码:
第一次尝试代码:
以十进制为媒介进行转化
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
String[] a = new String[n];
for(int i=0;i<a.length;i++){
a[i] = sc.next();
}
for(int i=0;i<a.length;i++){
//将字符串转化成字符数组带入转化成十进制
char b[] = a[i].toCharArray();
Long m = num(b);
zhuanhua(m);
}
}
// 将十六进制转化为十进制
public static long num(char a[]){
long sum=0;
for(int i=0;i<a.length;i++){
if(a[i]<='9'&&a[i]>='0'){
sum += (int)(a[i] - '0') * Math.pow(16, a.length-i-1);
}else if(a[i]<='F' && a[i]>='A'){
sum += ((int)(a[i] - 'A') + 10) * Math.pow(16, a.length-i-1);
}
}
return sum;
}
//将十进制转化为八进制
public static void zhuanhua(Long num){
long sum = 0;
long k = 1;
while(num != 0){
sum = sum + (num % 8) * k;
num /= 8;
k *= 10;
}
System.out.println(sum);
}
}
但很可惜这种方法走不通,以为忽略了一个问题:当十六进制转化成十进制的时候,十进制这个媒介需要用数字来接收,那么可能就会出现这样一种情况十六进制的这个数很大以至于转化成十进制后用long型去接收都会溢出
。
第二次尝试:
那如果想不考虑数字大小完成转换,我们就不能选择用数字去接收,所以此时我就思考能不能有什么媒介,可以让他从始至终都使用字符进行转换,这个时候我就想起了二进制的特性o( ̄︶ ̄)o,二进制的话每相邻的四位是十六进制的一位,每相邻的三位是八进制的一位这样的话用二进制作为媒介就可以避开数字用字符串进行转换了,就可以避免数字溢出的情况了,下面把代码展现给大家:
第二次尝试代码:
以二进制为媒介进行转换
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
String[] strs = new String[n];
String str;
for(int i=0;i<n;i++){
strs[i] = sc.next();
}
for(int i=0;i<n;i++){
str = to_2(strs[i]);
to_8(str);
}
}
//十进制转化成二进制
public static String to_2(String a){
char nums[] = a.toCharArray();
String sum = "";
String t;
for(int i=0;i<nums.length;i++){
// 每一位十六进制转换为四位二进制储存进字符串
if(i!=0){
switch(nums[i]){
case '0': t= "0000"; break;
case '1': t= "0001"; break;
case '2': t= "0010"; break;
case '3': t= "0011"; break;
case '4': t= "0100"; break;
case '5': t= "0101"; break;
case '6': t= "0110"; break;
case '7': t= "0111"; break;
case '8': t= "1000"; break;
case '9': t= "1001"; break;
case 'A': t= "1010"; break;
case 'B': t= "1011"; break;
case 'C': t= "1100"; break;
case 'D': t= "1101"; break;
case 'E': t= "1110"; break;
case 'F': t= "1111"; break;
default : t= "";
}
}else{
//i== 0即最高位单独判断避免最高位为0的情况出现
switch(nums[i]){
case '1': t= "1"; break;
case '2': t= "10"; break;
case '3': t= "11"; break;
case '4': t= "100"; break;
case '5': t= "101"; break;
case '6': t= "110"; break;
case '7': t= "111"; break;
case '8': t= "1000"; break;
case '9': t= "1001"; break;
case 'A': t= "1010"; break;
case 'B': t= "1011"; break;
case 'C': t= "1100"; break;
case 'D': t= "1101"; break;
case 'E': t= "1110"; break;
case 'F': t= "1111"; break;
default : t= "";
}
}
sum = sum + t;
}
return sum;
}
//将二进制转换为八进制
public static void to_8(String a){
//二进制转化为八进制之前先补零
if(a.length()%3 == 2){
a = "0" + a;
}else if(a.length()%3 == 1){
a = "00" + a;
}
int length = a.length()/3;
char nums[] = a.toCharArray();
int sum[] = new int[length];
//每三位进行转换储存在字符数组中
for(int i = 0 ; i < length ; i++){
sum[i] = (int)(nums[3*i+2]-'0')+(int)(nums[3*i+1]-'0')*2+(int)(nums[3*i]-'0')*4;
}
for(int i = 0 ; i<length ; i++){
// 输出字符数组
System.out.print(sum[i]);
}
System.out.println();
}
}
这种方法就可以解决掉溢出问题了,我在编译器上使用也没什么问题,就当我觉得已经解决了的时候新的问题出现了:因为代码不够简洁运行时时间超时了
,但学C的小伙伴完全可以使用这种思路来写,C还是不容易超时的。
第三次尝试:
其实大致思路确实是这样但我忽略了一个很重要的东西,java有很多方法呀,咋们完全可以使用这些方法来解题。但在放代码时,考虑到大家可能跟我一样也忘了这些函数,我先用代码的方式简单的介绍一下这些方法:
public class Main1 {
public static void main(String[] args){
int n = 18;
// 输出都是字符串
System.out.println(n+"的二进制是:"+Integer.toBinaryString(n));
System.out.println(n+"的八进制是:"+Integer.toOctalString(n));
System.out.println(n+"的十六进制是:"+Integer.toHexString(n));
System.out.println(n+"的三进制是:"+Integer.toString(n,3));
}
}
在了解进制转化的方法之后,我们就来看看怎么用方法来解决这个问题吧,代码如下:
第三次尝试代码:
运用方法将十六进制转换为二进制再转换为八进制
import java.util.Scanner;
public class test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for(int i=0;i<n;i++){
String line = sc.next();
StringBuilder builder = new StringBuilder();
for(int k = 0 ; k < line.length() ; k++){
//substring从beginIndex开始取,到endIndex结束,从0开始数,其中不包括endIndex位置的字符
builder.append(HexToBin(line.substring(k, k+1)));
}
String bin = format3(builder.toString());
builder = new StringBuilder();
for (int j = 0; j < bin.length(); j+=3) {
builder.append(BinToOct(bin.substring(j, j+3)));
}
String result = builder.toString();
// 去除前面所有的零
int m = 0;
while(result.charAt(m) == '0'){
result = result.substring(m+1);
m++;
}
System.out.println(result);
}
}
// 十六进制转二进制
public static String HexToBin(String hex) {
//valueOf可以将基本类型int转换为包装类型Integer,或者将String转换成Integer,在这里把十六进制的字符串转化为十进制的int类型
return format4(Integer.toBinaryString(Integer.valueOf(hex, 16)));
}
public static String BinToOct(String Bin){
return Integer.toOctalString(Integer.valueOf(Bin,2));
}
// 十六进制转二进制补零
public static String format4(String str){
if(str.length()%4 == 3){
str = "0" + str;
}else if(str.length()%4 == 2){
str = "00" + str;
}else if(str.length()%4 == 1){
str = "000" + str;
}
return str;
}
// 八进制补零
public static String format3(String str){
if(str.length()%3 == 2){
str = "0" + str;
}else if(str.length()%3 == 1){
str = "00" + str;
}
return str;
}
}
对于蓝桥杯训练这道题来说只有第三种方法可以通过编译,之所以把三种方法都展示出来主要是想还原的我一个思考过程
,希望能够给大家带来更多的帮助,其他两种方法跳出蓝桥杯编译环境的印象也是有可取性的,最后感谢大家的观看和支持,快要过年了,也在此祝大家新年快乐
o( ̄︶ ̄)o