本来想偷懒用Java的 Long.parseLong(str, 16)
来将字符串转为十进制数,进而转八进制数。结果因为长度不够产生溢出,万般无奈只好从头开始写进制转换
整体思路就是:
- 十六进制字符串转二进制字符数组
- 二进制字符数组转八进制字符数组
- 输出结果
因为报的是Java组,所以没考虑C++实现。不过感觉还是写的复杂了些,后面有时间再看看怎么优化吧!
具体代码:
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// 第一步,收参
Scanner in = new Scanner(System.in);
int n = in.nextInt();
ArrayList<String> strings = new ArrayList<>(n); // 直接给定大小防止扩容浪费时间
for (int i = 0; i < n; ++i) {
strings.add(in.next());
}
char binary[]; // 二进制数组
char oct[]; // 八进制数组
for (String s : strings) {
// 先计算二进制数组的长度,注意要为3的倍数,不然后面转八进制数组会越界
int binary_size = s.length() * 4 + (3 - (s.length() * 4 % 3));
// 第二步,十六进制转二进制
binary = new char[binary_size];
for (int i = 0; i < binary_size; ++i) // 字符数组赋初值,不然不是'0'而是ASCII的0
binary[i] = '0';
int bCur = binary_size - 1; // bCur为二进制数组的游标
for (int i = s.length() - 1; i >= 0; --i) {
// 从尾部遍历十六进制字符串,并将每一位十六进制转为四位二进制
switch (s.charAt(i)) {
case '0': {
binary[bCur - 3] = '0';
binary[bCur - 2] = '0';
binary[bCur - 1] = '0';
binary[bCur] = '0';
break;
}
case '1': {
binary[bCur - 3] = '0';
binary[bCur - 2] = '0';
binary[bCur - 1] = '0';
binary[bCur] = '1';
break;
}
case '2': {
binary[bCur - 3] = '0';
binary[bCur - 2] = '0';
binary[bCur - 1] = '1';
binary[bCur] = '0';
break;
}
case '3': {
binary[bCur - 3] = '0';
binary[bCur - 2] = '0';
binary[bCur - 1] = '1';
binary[bCur] = '1';
break;
}
case '4': {
binary[bCur - 3] = '0';
binary[bCur - 2] = '1';
binary[bCur - 1] = '0';
binary[bCur] = '0';
break;
}
case '5': {
binary[bCur - 3] = '0';
binary[bCur - 2] = '1';
binary[bCur - 1] = '0';
binary[bCur] = '1';
break;
}
case '6': {
binary[bCur - 3] = '0';
binary[bCur - 2] = '1';
binary[bCur - 1] = '1';
binary[bCur] = '0';
break;
}
case '7': {
binary[bCur - 3] = '0';
binary[bCur - 2] = '1';
binary[bCur - 1] = '1';
binary[bCur] = '1';
break;
}
case '8': {
binary[bCur - 3] = '1';
binary[bCur - 2] = '0';
binary[bCur - 1] = '0';
binary[bCur] = '0';
break;
}
case '9': {
binary[bCur - 3] = '1';
binary[bCur - 2] = '0';
binary[bCur - 1] = '0';
binary[bCur] = '1';
break;
}
case 'A':
case 'a': {
binary[bCur - 3] = '1';
binary[bCur - 2] = '0';
binary[bCur - 1] = '1';
binary[bCur] = '0';
break;
}
case 'B':
case 'b': {
binary[bCur - 3] = '1';
binary[bCur - 2] = '0';
binary[bCur - 1] = '1';
binary[bCur] = '1';
break;
}
case 'C':
case 'c': {
binary[bCur - 3] = '1';
binary[bCur - 2] = '1';
binary[bCur - 1] = '0';
binary[bCur] = '0';
break;
}
case 'D':
case 'd': {
binary[bCur - 3] = '1';
binary[bCur - 2] = '1';
binary[bCur - 1] = '0';
binary[bCur] = '1';
break;
}
case 'E':
case 'e': {
binary[bCur - 3] = '1';
binary[bCur - 2] = '1';
binary[bCur - 1] = '1';
binary[bCur] = '0';
break;
}
case 'F':
case 'f': {
binary[bCur - 3] = '1';
binary[bCur - 2] = '1';
binary[bCur - 1] = '1';
binary[bCur] = '1';
break;
}
}
bCur -= 4; // 每一位十六进制对应四位二进制,所以游标每次减4
}
// 第三步,二进制转八进制
// 每三位二进制对应一位八进制,所以八进制数组是二进制数组的1/3
oct = new char[binary_size / 3];
int oCur = oct.length - 1; //
String temp;
for (int i = binary_size - 1; i >= 0; i -= 3) {
// 每三位二进制对应一位八进制,所以循环的步长为3
// 使用StringBuilder拼接字符,便于switch中使用进行字符串比对
StringBuilder sb = new StringBuilder();
sb.append(binary[i - 2]);
sb.append(binary[i - 1]);
sb.append(binary[i]);
temp = sb.toString();
switch (temp) {
case "000": {
oct[oCur] = '0';
break;
}
case "001": {
oct[oCur] = '1';
break;
}
case "010": {
oct[oCur] = '2';
break;
}
case "011": {
oct[oCur] = '3';
break;
}
case "100": {
oct[oCur] = '4';
break;
}
case "101": {
oct[oCur] = '5';
break;
}
case "110": {
oct[oCur] = '6';
break;
}
case "111": {
oct[oCur] = '7';
break;
}
}
oCur--;
}
// 第四步,输出结果
for (int i = 0; i < oct.length; ++i) {
if (i == 0) {
if (oct[i] == '0') // 第一位有0的话不输出
continue;
}
System.out.print(oct[i]);
}
System.out.println();
}
}
}
感觉需要注意的就是转换是从右往左转的(用栈的话思路应该更清晰一些),还有就是数组越界问题要考虑清楚,尤其是二进制转八进制的部分容易出错。