首先对等待程序猿成长之路系列的小伙伴们说声抱歉,春节来临,可能要拖更一段时间,但是草稿已经在写,发布将会于春节后进行发布
春节第一天闲着无聊打算找个蓝桥杯的题目练练手,诶嘿,这就找到一题,话不多说,上题
题目
题目很好理解,就是要输入n个数,将其从十六进制转成八进制。一般的做法也如这里提示所说。要先转成10进制后转成八进制,但我认为先转成10进制会浪费计算机的算力并且提高了算法的时间复杂度,这种转换是完全可以进行优化的。
我的优化算法思路
我的算法是直接将16进制转乘8进制,算法有如下几点要求:
- 输入的内容为字符串,这样可以进行大数运算
- 最多只能使用一重for循环,以降低算法的时空复杂度。
- 返回的值也为字符串
下面来介绍一下我的算法:
- 将输入的字符串转化为字符数组
- 从低位(即数组的最高位)开始,进行运算:
1. 因为是从16进制转8进制,为了保持数据一致,八进制上每位数字的数可以认为是原数同一位置上的 2 的幂次倍,这样说可能比较难以理解,那我就举个例子,(10)16 = (16)10 = (20)8 这里 十六进制上的首位(从低位数起第2位)为1,到了八进制就为2,也就是 1 * 2的1次方,(100)16 = (256)10 = (400)10 ,这里 十六进制上的首位(从低位数起第3位)为1,到了八进制就为4,也就是 1 * 2的2次方,以此类推。
2. 但是要注意,低位会像高位进位,这里的进位数字要进行保存,我们用incr参数进行保存,在进行换算时要加上低位向高位的进位。
3. 此外当前位上的数字进行了转换(乘以了 2 的幂次倍) + 进位很可能超过8,这时候我们要进行取余运算获取最后的小于8的值即为八进制该位上的数字。而进位也要继续保存,方便下一步的运算。
4. 按照步骤1-3计算从低位到高位上每一位的八进制结果,要注意的是,首位数字可能会有进位,这时就需要对进位进行处理,处理方法与步骤2-3步类似。
代码
package hexToOct;
public class HexToOct {
/**
* 十六进制转八进制
* 原理:1. 从低位往高位处理,每升一位*2
* @param args
*/
private static String hexToOct(String hex) {
char[] ch = hex.toCharArray(); //step1
StringBuilder builder = new StringBuilder();
int i = 0, incr = 0; // incr - 累进数, rest - 余数
//step2
for (int j = ch.length-1; j>= 0; j--) {
int numb = 0;
// 将十六进制转10进制
if (ch[j] >= '0' && ch[j] <= '9') {
numb = Integer.valueOf(ch[j] - '0');
} else if(ch[j] >= 'A' && ch[j] <= 'F') {
numb = Integer.valueOf(ch[j] - 'A') + 10;
} else {
System.out.println("请输入十六进制数");
return null;
}
// 处理每一位上的数字
numb = numb << (i++); // numb = numb * (2^i); i = i + 1;
numb += incr;
incr = numb / 8; // 求累进数,便于加入下一次的运算
numb = numb % 8; // 求当前的余数
builder.append(numb + "");
}
//考虑首位进位的情况
int rest = 0;
if (incr != 0) {
while(incr > 0) {
rest = incr % 8;
incr = incr / 8;
builder.append(rest + "");
}
}
return builder.reverse().toString();
}
public static void main(String[] args) {
System.out.println(hexToOct("8A24B"));
}
}
运算结果
2121113
算法复杂度
O(n)