问题描述
给定n个十六进制正整数,输出它们对应的八进制数。
输入格式
输入的第一行为一个正整数n (1<=n<=10)。
接下来n行,每行一个由0~9、大写字母A~F组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过100000。
接下来n行,每行一个由0~9、大写字母A~F组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过100000。
输出格式
输出n行,每行为输入对应的八进制正整数。
注意
输入的十六进制数不会有前导0,比如012A。
输出的八进制数也不能有前导0。
输出的八进制数也不能有前导0。
样例输入
2
39
123ABC
39
123ABC
样例输出
71
4435274
4435274
提示
先将十六进制数转换成某进制数,再由某进制数转换成八进制。
代码:
先贴c++的代码:
#include<iostream> #include<string> using namespace std; void toOx(string s) { int t = s.length() % 3; if (t != 0) { for (int i = 0; i < 3 - t; ++i) { s = '0' + s; } } int sum = 0; bool notZ = false; for (int i = 0; i < s.length(); i += 3) { sum = 0; for (int j = 0; j < 2; ++j) { sum += (s[i + j] == '0') ? 0 : 2 * (2 - j); } sum += (s[i + 2] == '0') ? 0 : 1; if (sum == 0 && !notZ) { notZ = true; } else { notZ = true; cout << sum; } } cout << endl; } string toBin(string s) { string st = ""; for (int i = 0; i < s.length(); ++i) { switch (s[i]) { case '0': st += "0000"; break; case '1': st += "0001"; break; case '2': st += "0010"; break; case '3': st += "0011"; break; case '4': st += "0100"; break; case '5': st += "0101"; break; case '6': st += "0110"; break; case '7': st += "0111"; break; case '8': st += "1000"; break; case '9': st += "1001"; break; case 'A': st += "1010"; break; case 'B': st += "1011"; break; case 'C': st += "1100"; break; case 'D': st += "1101"; break; case 'E': st += "1110"; break; case 'F': st += "1111"; break; } } return st; } int main() { int n; cin >> n; string *s = new string[n]; for (int i = 0; i < n; ++i) { cin >> s[i]; } for (int j = 0; j < n; ++j) { toOx(toBin(s[j])); } delete[]s; string st; return 0; }
后是java的代码(和c++逻辑是一样的):
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); String s[] = new String[n]; for (int i = 0; i < n; ++i) { s[i] = in.next(); } in.close(); for (int i = 0; i < s.length; ++i) { toOx(toBin(s[i])); } } public static String toBin(String s) { char[] a = s.toCharArray(); String st = ""; for (int i = 0; i < s.length(); ++i) { switch (a[i]) { case '0': st += "0000"; break; case '1': st += "0001"; break; case '2': st += "0010"; break; case '3': st += "0011"; break; case '4': st += "0100"; break; case '5': st += "0101"; break; case '6': st += "0110"; break; case '7': st += "0111"; break; case '8': st += "1000"; break; case '9': st += "1001"; break; case 'A': st += "1010"; break; case 'B': st += "1011"; break; case 'C': st += "1100"; break; case 'D': st += "1101"; break; case 'E': st += "1110"; break; case 'F': st += "1111"; break; } } return st; } public static void toOx(String s) { int t = s.length() % 3; if (t != 0) { for (int i = 0; i < 3 - t; ++i) { s = 0 + s; } } int sum = 0; boolean notZ = false; char[] a = s.toCharArray(); for (int i = 0; i < s.length(); i += 3) { sum = 0; for (int j = 0; j < 2; ++j) { sum += (a[i + j] == '0') ? 0 : 2 * (2 - j); } sum += (a[i + 2] == '0') ? 0 : 1; if (sum == 0 && !notZ) { notZ = true; } else { notZ = true; System.out.print(sum); } } System.out.println(); } }
这里说下这个题,我总共提交了16次,开始我只提交了java版本,但是一直是运行超时,后来我又开始提交c++版本,试了几次之后,最终提交成功,100分,109ms,就是上面的代码,然后我紧接着改写成java代码,然后再提交,但还是运行超时,最后只好放弃java版本。
因为我提交了16次,所以这里多说些,关于这个算法,最初我想的是十六进制先转换成十进制,在转换成八进制,因为前面有一道题是十六进制转十进制的,这样的话可以偷下懒,但是提交了几次总是出错,后来仔细看题发现“每个十六进制数长度不超过100000”,那就说明测试数据会有至少一个长度是100000的十六进制数,所以转换成十进制的想法是不对的,应该转化成二进制,一位十六进制数是四位二进制,三位二进制数是一位八进制,应该按这个思路进行。
这里最简单的方法就是把十六进制转换成一个二进制字符串,然后使用switch把三位二进制转化成一位八进制,我用java这样试过几次,但是还是超时,最终放弃,后来想到可以用算数的方法计算八进制(我也不清楚到底哪种方法更快,我没在c++里使用过前面说的switch方法),就像代码里写的那样。最终几次尝试,终于成功。还有因为对速度要求比较高,所以尽量在原串上进行操作,能不提取字符串就不提取,我也试过使用类似substring的方法在长串里提取三个字符,但是超时了。还有几次都是因为自己的疏忽而导致运行错误,下次更细心些,引以为戒好了。
(最后更新下,java代码,在toBin方法里,把String对象st改成StringBuffer,把+=改成append().超时问题就解决了)