问题描述
给定n个十六进制正整数,输出它们对应的八进制数。
输入格式
输入的第一行为一个正整数n (1<=n<=10)。
接下来n行,每行一个由0~9、大写字母A~F组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过100000。
输出格式
输出n行,每行为输入对应的八进制正整数。
【注意】
输入的十六进制数不会有前导0,比如012A。
输出的八进制数也不能有前导0。
样例输入
2
39
123ABC
样例输出
71
4435274
【提示】
先将十六进制数转换成某进制数,再由某进制数转换成八进制。
1. 用已有的函数,因为测试的数据非常大故会超出范围;
已有的函数:(Integer.toBinaryString/toHexString/toOctalString and Integer.valueOf("FFF",16));PS:这些函数以十进制衔接;
2. 3位16进制数等于4位8进制数(转化为二进制看),十六进制 A1 二进制 1010 0001 八进制 (010 100 001)241;
3.当5位十六进制数→二进制数→八进制数,在二进制转换为八进制的时候会出现不够数目,需要在二进制前补“3-二进制数.length()”个零;
初步代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
// String[] st={"000","001","010","011","100","101","110","111"};
for(int i=0;i<n;i++){
String str=sc.next();
String sb=new String();
for(int j=0;j<str.length();j++){
String str1=Integer.toBinaryString(Integer.valueOf(String.valueOf(str.charAt(j)),16));
for(int m=str1.length();m<4;m++){
str1="0"+str1;
}
sb=sb.concat(str1);//二进制字符串
}
int zeros=3-sb.length()%3;
for(int m=0;m<zeros;m++){
sb="0"+sb;
}
for(int m=0;m<sb.length();m+=3){
String str2=sb.substring(m,m+3);
// for(int o=0;o<8;o++){
// if(str2.equals(st[o]))
// {
// System.out.print(o);
// }
// }
System.out.print(Integer.toOctalString(Integer.valueOf(str2, 2)));
}
}
sc.close();
}
}
问题:超时
优化:1.取消最后的中间十进制转换,放弃函数,列表直接转换为八进制;
2.上面代码注释掉的部分是第一次优化的部分;
优化改正:
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
String[] st={"000","001","010","011","100","101","110","111"};
for(int i=0;i<n;i++){
String str=sc.next();
String sb=new String();
for(int j=0;j<str.length();j++){
String str1=Integer.toBinaryString(Integer.valueOf(String.valueOf(str.charAt(j)),16));
for(int m=str1.length();m<4;m++){
str1="0"+str1;
}
sb=sb.concat(str1);//二进制字符串
}
int zeros=3-sb.length()%3;
for(int m=0;m<zeros;m++){//为八进制做准备补零
sb="0"+sb;
}
String str3=new String();
for(int m=0;m<sb.length();m+=3){
String str2=sb.substring(m,m+3);
for(int o=0;o<8;o++){
if(str2.equals(st[o])){
str3=str3.concat(Integer.valueOf(o).toString());
}
}
}
while(str3.charAt(0)==0){//去掉残留的先导零
str3=str3.replaceFirst("[0]", "");
}
System.out.print(str3);
}
sc.close();
}
}
问题:上代码中,加大加粗部分,str3.charAt(0)==30 或者是str3.charAt(0)==0 始终是false,不明白原因,JDK上说charAt()是返回char值,不太明白char值,必应了一下(http://www.cnblogs.com/tian_z/archive/2010/08/06/1793736.html)无论是这个文章里的char值还是ASCII码都不能使判断成立(true)
用charAt()返回的是char值,用codePointAt()会返回ASCII码值的十进制。
上述问题部分可改为:
while(str3.codePointAt(0)==48){//去掉残留的先导零
str3=str3.replaceFirst("^0", "");
}
System.out.print(str3);
就可以去掉先导零了。
尝试用正则表达式和replaceAll在匹配不到时候会产生错误用try catch来弄:
try{
str3=str3.replaceAll("^0", "");
}
catch(Exception e){
System.out.print(str3);
}
结果:不成功,准备去参考一下别人的代码;
参考结果:正则表达式写的不好。。。应该是
str3=str3.replaceAll("^0+", "");
System.out.println(str3);
优化过后代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
String[] st={"000","001","010","011","100","101","110","111"};
for(int i=0;i<n;i++){
String str=sc.next();
String sb=new String();
for(int j=0;j<str.length();j++){
String str1=Integer.toBinaryString(Integer.valueOf(String.valueOf(str.charAt(j)),16));
for(int m=str1.length();m<4;m++){
str1="0"+str1;
}
sb=sb.concat(str1);//二进制字符串
}
int zeros=3-sb.length()%3;
for(int m=0;m<zeros;m++){//为八进制做准备补零
sb="0"+sb;
}
String str3=new String();
for(int m=0;m<sb.length();m+=3){
String str2=sb.substring(m,m+3);
for(int o=0;o<8;o++){
if(str2.equals(st[o])){
str3=str3.concat(Integer.valueOf(o).toString());
}
}
}
str3=str3.replaceAll("^0+", "");
System.out.println(str3);
}
sc.close();
}
}
结果:依旧超时。。。
继续优化:1.把所有字符串粘接用StringBuilder.append(String arg0),比String.concat(String arg0)的速度要快得多;
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
String[] st={"000","001","010","011","100","101","110","111"};
for(int i=0;i<n;i++){
String str=sc.next();
StringBuilder sb=new StringBuilder();
for(int j=0;j<str.length();j++){
String str1=Integer.toBinaryString(Integer.valueOf(String.valueOf(str.charAt(j)),16));
for(int m=str1.length();m<4;m++){
str1="0"+str1;
}
sb=sb.append(str1);//二进制字符串
}
int zeros=3-sb.length()%3;
for(int m=0;m<zeros;m++){//为八进制做准备补零
sb=new StringBuilder("0").append(sb);
}
StringBuilder str3=new StringBuilder();
for(int m=0;m<sb.length();m+=3){
String str2=sb.substring(m,m+3);
for(int o=0;o<8;o++){
if(str2.equals(st[o])){
str3=str3.append(Integer.valueOf(o).toString());
}
}
}
String str4=str3.toString().replaceAll("^0+", "");
System.out.println(str4);
}
sc.close();
}
}
结果:可以了
后记改动:
真的是很好玩,进制转换全部使用已有的方法Integer.toBinaryString() 等方法,通过十进制为媒介转换到八进制速度比自己列表用If判断要快
优化代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args){
long start=System.currentTimeMillis();// 记录起始时间
try { // 线程睡眠5秒,让运行时间不那么小
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
for(int i=0;i<n;i++){
String str=sc.next();
StringBuilder sb=new StringBuilder();
for(int j=0;j<str.length();j++){
String str1=Integer.toBinaryString(Integer.valueOf(String.valueOf(str.charAt(j)),16));
for(int m=str1.length();m<4;m++){
str1="0"+str1;
}
sb=sb.append(str1);//二进制字符串
}
int zeros=3-sb.length()%3;
for(int m=0;m<zeros;m++){//为八进制做准备补零
sb=new StringBuilder("0").append(sb);
}
StringBuilder str3=new StringBuilder();
String o=new String();
for(int m=0;m<sb.length();m+=3){
String str2=sb.substring(m,m+3);
o=Integer.toOctalString(Integer.valueOf(String.valueOf(str2), 2));
str3=str3.append(o);
}
String str4=str3.toString().replaceAll("^0+", "");
System.out.println(str4);
}
sc.close();
long end=System.currentTimeMillis();
// 记录结束时间
System.out.println("用时:"+(end-start));// 相减得出运行时间
}
}
System.currentTimeMillis() 用来自测程序跑了多久时间
1.String.valueOf(),可以返回各个其他类型的字符串形式,具体看JDK