题目重点:按指数位迭代平方,把负指数取反前先扩宽整数,并核对零底数、精度和浮点边界。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练版返回浮点数,n 为整数;0 的负次方抛 ZeroDivisionError,任何非零底数的零次方及 0⁰ 都按 1.0。具体 0⁰ 契约题目未明确。
- 代码语言 Python 自带无限精度整数,但文章以 32 位有符号 n 解释 INT_MIN 风险;在 Java/C++ 应先转 64 位再取负。
解题路线
- 基线乘 |n| 次是 O(|n|)。快速幂利用 xⁿ:若 n 的低位为 1,将当前 factor 乘入结果;每轮 factor 平方、n 右移一位,O(log |n|) 次。
- 负 n 先用宽整数取绝对值,求完正幂后取倒数;不能在 32 位 int 中先写 `-n`,因为 -INT_MIN 无法表示。
- 递归版用 n 偶数→pow(x,n/2)²、奇数→x×pow(x,(n-1)/2),深度 O(log |n|);迭代版避免调用栈并易于控制中间溢出。
- 真实浮点库还需规定 NaN、±∞、带符号零和 overflow/underflow;面试手写题应先确认是否需要完整 IEEE 754 语义。
手动走一遍
2⁻³:先取宽整数指数 3,二进制 11,依次乘 2 和 4 得 8,再取倒数 1/8。n=−2³¹ 时先转 64 位再取负,可得 2³¹ 这个正指数。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
def fast_power(base: float, exponent: int) -> float:
if base == 0 and exponent < 0:
raise ZeroDivisionError("zero to negative power")
if exponent == 0:
return 1.0
# In a fixed-width language, widen exponent before negating INT_MIN.
n = -int(exponent) if exponent < 0 else int(exponent)
factor = float(base)
result = 1.0
while n:
if n & 1:
result *= factor
factor *= factor
n >>= 1
return 1.0 / result if exponent < 0 else result
复杂度
迭代 O(log |n|) 乘法、O(1) 额外空间;递归 O(log |n|) 时间和栈。浮点乘法视为 O(1) 是固定字长模型,任意精度数字需计位复杂度。训练代码 20,000 组随机值与 Python 幂运算对照。
易错点与追问
容易失分的边界
- 在固定宽整数中先 `-INT_MIN`。
- 负指数忘记取倒数。
- 0 的负次方默默返回 0。
- 把平方操作放在判断前导致低位乘错。
- 声称与标准数学库对 NaN/∞ 完全一致却没有定义。
继续深挖
- 递归与迭代的栈空间差别?
- 若结果是整数模 M,如何改成模幂?
- 大指数下浮点 underflow 如何报告?
- 0⁰ 在产品 API 中应怎样定义?
