1. 问题背景与需求解析
今天要讨论的是一个来自LeetCode的进制转换问题(编号3602)。题目要求我们实现一个函数,输入一个整数n,输出一个特定格式的字符串。这个字符串由两部分组成:n²的十六进制表示和n³的三十六进制表示,两部分拼接后统一转为大写。
这类进制转换问题在实际开发中其实很常见。比如在短链接生成、ID编码、哈希值表示等场景,我们经常需要将数字转换为更紧凑的字符串形式。理解不同进制间的转换原理,对提升我们的编码能力很有帮助。
2. 核心思路与算法设计
2.1 问题分解
这个任务可以分解为三个主要步骤:
- 计算n的平方(n²)
- 计算n的立方(n³)
- 将这两个结果分别转换为指定进制的字符串表示
2.2 Java内置方法的选择
Java标准库提供了非常方便的进制转换方法:
Integer.toHexString():专门用于十进制转十六进制Integer.toString(int i, int radix):通用进制转换方法,radix参数指定目标进制
注意:这些方法生成的字符串默认使用小写字母表示10-35的数字。题目要求最终结果为大写,所以需要额外调用toUpperCase()方法。
2.3 边界条件考虑
虽然题目没有明确说明,但实际实现时需要考虑:
- 输入n为0的情况(0²和0³都是0)
- 输入n为负数的情况(平方和立方后都变为正数)
- 大整数情况(虽然题目参数是int,但n³可能接近int最大值)
3. 完整代码实现与解析
class Solution { public String concatHex36(int n) { // 计算n的平方并转为16进制 String hexPart = Integer.toHexString(n * n); // 计算n的立方并转为36进制 // 36进制使用0-9和a-z表示数值 String base36Part = Integer.toString(n * n * n, 36); // 拼接并转为大写 return (hexPart + base36Part).toUpperCase(); } }3.1 代码逐行解析
n * n:计算n的平方。这里直接使用乘法运算符,时间复杂度O(1)Integer.toHexString():将平方结果转为16进制字符串- 内部实现是通过不断除以16并取余数
- 例如:100 → "64"(16×6 + 4)
n * n * n:计算n的立方Integer.toString(..., 36):将立方结果转为36进制- 36进制使用0-9表示0-9,a-z表示10-35
- 例如:1000 → "rs"(27×36 + 28)
toUpperCase():将结果统一转为大写
3.2 测试用例示例
| 输入n | n² | 十六进制 | n³ | 三十六进制 | 输出结果 |
|---|---|---|---|---|---|
| 2 | 4 | "4" | 8 | "8" | "48" |
| 10 | 100 | "64" | 1000 | "rs" | "64RS" |
| 16 | 256 | "100" | 4096 | "2zs" | "1002ZS" |
4. 算法复杂度分析
4.1 时间复杂度
主要时间消耗在两个进制转换过程:
- 十六进制转换:O(log₁₆(n²)) ≈ O(2log₁₆n) ≈ O(logn)
- 三十六进制转换:O(log₃₆(n³)) ≈ O(3log₃₆n) ≈ O(logn)
其他操作(乘法、字符串拼接、大小写转换)都是O(1)或O(k)(k为字符串长度),所以总体时间复杂度为O(logn)。
4.2 空间复杂度
空间消耗主要来自生成的字符串:
- 十六进制字符串长度:⌈log₁₆(n²)⌉
- 三十六进制字符串长度:⌈log₃₆(n³)⌉
两者都与n的对数成正比,因此空间复杂度也是O(logn)。
5. 进阶思考与优化方向
5.1 不使用库函数的实现
虽然使用Java内置方法很方便,但理解底层实现也很重要。我们可以手动实现进制转换:
private String toBase(int num, int base) { if(num == 0) return "0"; StringBuilder sb = new StringBuilder(); while(num > 0) { int digit = num % base; char c = digit < 10 ? (char)('0' + digit) : (char)('a' + digit - 10); sb.append(c); num /= base; } return sb.reverse().toString(); }5.2 大数处理
当n较大时(接近Integer.MAX_VALUE),n³可能溢出。可以使用long类型避免这个问题:
public String concatHex36(int n) { long square = (long)n * n; long cube = square * n; String hexPart = Long.toHexString(square); String base36Part = Long.toString(cube, 36); return (hexPart + base36Part).toUpperCase(); }5.3 性能优化
对于高频调用的场景,可以预先计算并缓存36进制的字符映射关系:
private static final char[] DIGITS = "0123456789abcdefghijklmnopqrstuvwxyz".toCharArray(); private String fastToBase(int num, int base) { char[] buf = new char[32]; // 足够存放int的最大36进制表示 int pos = buf.length; do { buf[--pos] = DIGITS[num % base]; num /= base; } while (num != 0); return new String(buf, pos, buf.length - pos); }6. 实际应用场景
这种进制转换技术在以下场景很有用:
- 短URL生成:将数据库ID转换为更短的字符串
- 文件校验码:将哈希值表示为更紧凑的形式
- 序列号生成:将时间戳和随机数编码为易读的字符串
- 数据压缩:用更高进制的表示减少字符串长度
理解这些基础算法,能帮助我们在实际开发中选择合适的编码方案,优化存储和传输效率。