十六进制转八进制,超大测试数据

339 阅读5分钟

做蓝桥杯题目时碰到这样一题,这题有两个版本的,一种是小数据测试,一种是大数据测试。一开始觉得挺容易的,直接用的java内置的方法进行的进制转换,后来测试也通过了,这个链接里记录了这种简单方法。 juejin.cn/post/684490…

后来又碰到一次这种题目,怎么测试都通不过,后来才发现当传入一个比较变态的十六进制数时,系统自带的Java方法是不行的,超出了范围。只能全部用字符串处理,将十六进制转换成二进制,再从二进制转换成八进制。

下面是我重新写的,这种可以处理任意长度的十六进制数,但是因为算法复杂度太大,传入的数据比较多时,运算的时间比较长。

思路:

根据计算机原理,我们知道4位数的二进制可以完全表示十六进制,最大的4位二进制'1111'刚好等于十六进制中最大的数'F'.3位数的二进制可以完全表示八进制,最大的3位二进制'111'刚好等于八进制中最大的数'7'.所以对于这种超大的数据转换的时候我们可以使用字符串的方式进行转换。

package _3_5_test;

import java.math.BigInteger;
import java.util.Scanner;

import javax.sound.midi.Soundbank;

/*十六进制转八进制
 * 
 * 
 * */
public class eightteen {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Scanner scanner = new Scanner(System.in);

		int n = scanner.nextInt();

		// 十六进制
		String h = new String();
		// 二进制
		String b = new String();
		// 八进制
		String o[] = new String[n];

		for (int i = 0; i < n; i++) {
			// 接收十六进制数
			h = scanner.next();
			// 将十六进制数转换成二进制数
			b = heaxToBit(h);
			// 将二进制数转换成八进制
			o[i] = BitToOct(b);
			// 对八进制结果进行处理,去掉开头的0
			while (o[i].startsWith("0")) {
				o[i] = o[i].substring(1);
			}
		}

		// 结果输出
		for (String s : o) {
			System.out.println(s);
		}

	}

	// 自定义十六进制转二进制方法,返回字符串类型
	public static String heaxToBit(String s) {
		// 用于临时保存十六进制字符串中单个字符所对应的二进制
		String re = "";
		// 用于保存最终的二进制结果
		String result = "";

		for (int i = 0; i < s.length(); i++) {
			switch (s.substring(i, i + 1)) {
			case "0":
				re = "0000";
				break;
			case "1":
				re = "0001";
				break;
			case "2":
				re = "0010";
				break;
			case "3":
				re = "0011";
				break;
			case "4":
				re = "0100";
				break;
			case "5":
				re = "0101";
				break;
			case "6":
				re = "0110";
				break;
			case "7":
				re = "0111";
				break;
			case "8":
				re = "1000";
				break;
			case "9":
				re = "1001";
				break;
			case "A":
				re = "1010";
				break;
			case "B":
				re = "1011";
				break;
			case "C":
				re = "1100";
				break;
			case "D":
				re = "1101";
				break;
			case "E":
				re = "1110";
				break;
			case "F":
				re = "1111";
				break;
			default:
				break;
			}

			result = result + re;
		}

		return result;
	}

	// 自定义二进制转八进制方法
	public static String BitToOct(String s) {
		// 用于临时保存二进制字符串中单个字符所对应的八进制
		String re = "";
		// 用于保存最终的八进制结果
		String result = "";

		String getS = s;

		while ((getS.length() % 3) != 0) {
			getS = "0" + getS;
		}
		for (int i = 0; i < getS.length(); i = i + 3) {
			switch (getS.substring(i, i + 3)) {
			// 八进制表
			case "000":
				re = "0";
				break;
			case "001":
				re = "1";
				break;
			case "010":
				re = "2";
				break;
			case "011":
				re = "3";
				break;
			case "100":
				re = "4";
				break;
			case "101":
				re = "5";
				break;
			case "110":
				re = "6";
				break;
			case "111":
				re = "7";
				break;
			default:
				break;
			}
			result = result + re;
		}

		return result;
	}

}

大数据处理效果:

这种复杂度太大了,调用两个进制转换方法的时候复杂度达到了o(n^2),运行时间太长,我试着换种写法去降低算法复杂度。后来发现无论怎么精简代码,最终的代码复杂度还是o(n^2)。就试着从内存空间的角度去优化代码,再看看原代码发现,我在两个自定义的进制转换方法里都多次调用了String对象进行赋值。

String是不可变的对象,每次新的赋值都相当于重新创建一个对象再赋值,这样如果嵌套了两次循环的话占的内存空间是很大的,也会花费更多的时间。而StringBuffer是可拼接对象,每次追加内容直接在原有的基础上直接添加就行,不需要重新创建对象。

在我把String都替换成StringBuffer后再测试大型数据,发现可以正常通过了

package _3_5_test;

import java.math.BigInteger;
import java.util.Scanner;

import javax.sound.midi.Soundbank;

/*十六进制转八进制
 * 
 * 
 * */
public class eightteen {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Scanner scanner = new Scanner(System.in);

		int n = scanner.nextInt();

		// 十六进制
		String h = new String();
		// 二进制
		String b = new String();
		// 八进制
		String o[] = new String[n];

		for (int i = 0; i < n; i++) {
			// 接收十六进制数
			h = scanner.next();
			// 将十六进制数转换成二进制数
			b = heaxToBit(h);
			// 将二进制数转换成八进制
			o[i] = BitToOct(b);
			// 对八进制结果进行处理,去掉开头的0
			while (o[i].startsWith("0")) {
				o[i] = o[i].substring(1);
			}
		}

		// 结果输出
		for (String s : o) {
			System.out.println(s);
		}

	}

	// 自定义十六进制转二进制方法,返回字符串类型
	public static String heaxToBit(String s) {
		// 用于保存最终的八进制结果
		StringBuffer re = new StringBuffer();

		for (int i = 0; i < s.length(); i++) {
			switch (s.substring(i, i + 1)) {
			case "0":
				re.append("0000");
				break;
			case "1":
				re.append("0001");
				break;
			case "2":
				re.append("0010");
				break;
			case "3":
				re.append("0011");
				break;
			case "4":
				re.append("0100");
				break;
			case "5":
				re.append("0101");
				break;
			case "6":
				re.append("0110");
				break;
			case "7":
				re.append("0111");
				break;
			case "8":
				re.append("1000");
				break;
			case "9":
				re.append("1001");
				break;
			case "A":
				re.append("1010");
				break;
			case "B":
				re.append("1011");
				break;
			case "C":
				re.append("1100");
				break;
			case "D":
				re.append("1101");
				break;
			case "E":
				re.append("1110");
				break;
			case "F":
				re.append("1111");
				break;
			default:
				break;
			}

		}

		return re.toString();
	}

	// 自定义二进制转八进制方法
	public static String BitToOct(String s) {
		// 用于保存最终的八进制结果
		StringBuffer re = new StringBuffer();

		String getS = s;

		while ((getS.length() % 3) != 0) {
			getS = "0" + getS;
		}
		for (int i = 0; i < getS.length(); i = i + 3) {
			switch (getS.substring(i, i + 3)) {
			// 八进制表
			case "000":
				re.append("0");
				break;
			case "001":
				re.append("1");
				break;
			case "010":
				re.append("2");
				break;
			case "011":
				re.append("3");
				break;
			case "100":
				re.append("4");
				break;
			case "101":
				re.append("5");
				break;
			case "110":
				re.append("6");
				break;
			case "111":
				re.append("7");
				break;
			default:
				break;
			}

		}

		return re.toString();
	}

}