起初拿到这道题的时候,想着挺简单的,和大多数人一样,我选择使用了jdk中原有的api去实现这一功能
,代码如下:
//使用java自带函数进行进制的转换
//1.Scanner.nextInt读取的是一次的数据,返回String对象
//2.Integer.parseint(string,原进制数)可以将其他进制转换为10进制的数。
//3.Integer.toOctalString(int)将10进制转换为8进制数
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
// int arr[]=new int[10];
String srr[]=new String[10];
for(int i=0;i<n;i++) {
srr[i]=sc.next();
}
for(int i=0;i<n;i++) {
System.out.println(Integer.toOctalString(Integer.parseInt(srr[i],16)));
}
}
}
然而这个case显然没有通过蓝桥的测试系统。先说一下我查错的过程:
1.是否输入输出的格式不对。(后期证明跟格式没有关系。不需要你去可以控制输入的格式,测试用例输入
的都是标准格式。)
2.数据的大小,是否会越界的情况。(差其他人写的博客确实说明了这一点,测试数据特别大,涉及到用
Integer是行不通的)。
接下来分析一些这么写通不过测试的原因:
*Integer.parseInt(srr[i],16)这条语句可以将String类型的16进制数转换为10进制的,so如果数小的话当然
没得问题,可是
在16进制数特别大的时候,字符串存放的话当然没有问题,可惜转换成整数之后就会boom爆炸啦
。我选了一个简单数据进行了测试
控制台输入(FFFFFFFFFFFFFF)14个16进制数
结果如下:
所以确定了问题出现的地方,flag:所以jdk到底有没有直接能将16进制的字符串装换为10进制的字符串呢?
暂时我还没有查到所以我想等
之后有时间的话好好查一下,或者亲自写一写看看有没有思路.
之后的话我只能乖乖的亲自去写一个转换算法了,http://blog.youkuaiyun.com/sr_19930829/article/details/18677037
这位博主写的我觉得是我
可以接受的于是我改成了java版的,提交了上去,以为这样就可以大功告成了,可惜,因为c和java还是有些
不同的,所以我的java版直接超
时了。so我现在又该考虑到如何优化,让我的运行的时间可以缩短一点。我把运行超时的代码贴出来了;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
String[] arr=new String[11];
char[] arr1=null;
char[] arr2=null;
for(int i=0;i<n;i++) {
arr[i]=sc.next();
}
for (String string : arr) {
if(string!=null) {
parse(string,arr1,arr2);
System.out.println();
}
}
}
static void parse(String S1,char[] arr1,char[] arr2) {
String s2,s1;
s1=S1;
s2="";
arr1=s1.toCharArray();
for(int i=0;i<s1.length();i++)//遍历,字符串上加上每一位
{
switch(arr1[i])
{
case '0':s2+="0000";break;
case '1':s2+="0001";break;
case '2':s2+="0010";break;
case '3':s2+="0011";break;
case '4':s2+="0100";break;
case '5':s2+="0101";break;
case '6':s2+="0110";break;
case '7':s2+="0111";break;
case '8':s2+="1000";break;
case '9':s2+="1001";break;
case 'A':s2+="1010";break;
case 'B':s2+="1011";break;
case 'C':s2+="1100";break;
case 'D':s2+="1101";break;
case 'E':s2+="1110";break;
case 'F':s2+="1111";break;
default:break;
}
}
int len=s2.length();
if(len%3==1)//三个二进制为一位八进制,二进制串前面补0,确保二进制串的长度为3的倍数
s2="00"+s2;
else if(len%3==2)
s2="0"+s2;
int flag=0;
arr2=s2.toCharArray();
for(int i=0;i<=s2.length()-3;i+=3)
{
int num=4*(arr2[i]-'0')+2*(arr2[i+1]-'0')+(arr2[i+2]-'0');
if(num!=0)
flag=1;//忽略前导0
if(flag!=0)
System.out.print(num);
}
}
}
我分析了一下目前自己可以察觉到需要优化的地方,我在存储数据的时候使用的是String对象,s1的使用上没有什么不方便的
,可是在s2的时候问题就出来了。因为String的长度是不可变,在循环和switch中在对s2添加数据的时候相当于每次都需要重
新创建一个String对象之后再赋值给原有的s2,所以这部分一定是首先要优化的一部分,如何优化呢?我选择使用了StringBuilder
这个对象,这个对象是一个可变长度的对象,同学们可以自行查一下这个对象的说明。之后通过StringBuilder.append方法可以去
对s2进行添加数据,因为是可变长度,所以内部也不会进行多次的创建对象和赋值,so就能节省很多的时间了.我把修改后的代码也贴了上来.
import java.util.Scanner;
public class Coversion8to16 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
String[] arr=new String[11];
char[] arr1=null;
char[] arr2=null;
for(int i=0;i<n;i++) {
arr[i]=sc.next();
}
for (String string : arr) {
if(string!=null) {
parse(string,arr1,arr2);
System.out.println();
}
}
}
static void parse(String s1,char[] arr1,char[] arr2) {
//使用stringbuilder优化
StringBuilder s2=new StringBuilder();
arr1=s1.toCharArray();
for(int i=0;i<s1.length();i++)//遍历,字符串上加上每一位
{
switch(arr1[i])
{
case '0':s2.append("0000");break;
case '1':s2.append("0001");break;
case '2':s2.append("0010");break;
case '3':s2.append("0011");break;
case '4':s2.append("0100");break;
case '5':s2.append("0101");break;
case '6':s2.append("0110");break;
case '7':s2.append("0111");break;
case '8':s2.append("1000");break;
case '9':s2.append("1001");break;
case 'A':s2.append("1010");break;
case 'B':s2.append("1011");break;
case 'C':s2.append("1100");break;
case 'D':s2.append("1101");break;
case 'E':s2.append("1110");break;
case 'F':s2.append("1111");break;
default:break;
}
}
int len=s2.length();
// arr2=s2.toString().toCharArray();
if(len%3==1)//三个二进制为一位八进制,二进制串前面补0,确保二进制串的长度为3的倍数
// s2="00"+s2;
s2.insert(0,"00");
else if(len%3==2)
// s2="0"+s2;
s2.insert(0,"0");
int flag=0;
arr2=s2.toString().toCharArray();
// arr2=s2.toCharArray();
for(int i=0;i<=s2.length()-3;i+=3)
{
int num=4*(arr2[i]-'0')+2*(arr2[i+1]-'0')+(arr2[i+2]-'0');
if(num!=0)
flag=1;//忽略前导0
if(flag!=0)
System.out.print(num);
}
}
}
谈一谈修改过程中修改的几个点:
1.用s2.append("0000")带替了s2+=“”;
2.在对二进制补零的过程中因为不能使用+号在s2的开头添加0,所以使用了StringBuilder.insert(0,“00”)方法。和s2=s2+“00”的效果是一样的.
3.因为StringBuilder并没有toCharArray()方法,则先用了tostring方法装换为了String对象后使用了toCharArray()方法。
虽然测试通过了可是还是不太满意的,可以看到时间和内存的消耗还是挺大的,已经在电脑前做了好久了,等找个时间一定要在好好的改一改这个代码。第一次码博客,写的不好请各位谅解。接受大家批评。