面试官问我x^n , 被我玩坏了 (爽文版) -- 一道华为od算法题从迭代->递归->快速幂 , 秒变快男 !

225 阅读4分钟

面试官 : 请用代码实现 x^n

我: 面试官我想确认一下 , x 和 n 的范围 , 因为数据类型表示数是有极限的 , 比如在 javaScript 中,如果 x,n 太大我可能要使用 bigint 来保证结果不溢出 , 甚至超过 bigint 的范围,我可能要使用字符串来计算并表示最终结果 , 所以我想请问面试官 ,对 x ,n 有没有具体的范围 ?

面试官 : 好的 , 数据保证在合理范围内 ,无需担心溢出问题 , 主要写你的思路 。

我(心理活动) : 有点小紧张 ! 先来个稳妥的 , 憋着大招后面放🤡

撸码中 ...

: 面试官请看下面代码


  function f(x,n){
    ans = 1;
    for(let i=0;i<n;i++){
        ans *= x;
    }
    return ans;
}
  

这是我采用迭代的方法 , 对 x 进行累乘 。

面试官 : 还有其他写法吗 ?

我(窃喜) : 好的面试官 , 我将为您带来递归的写法。

function g(x,n){
    if(n === 0) return 1;
    return x*g(x,n-1);
}

面试官 : 为什么这道题可以使用递归 ?

: 好的 , 面试官 。 (内心 : 请看我表演)

因为所谓递归 ,在我看来就是递推 + 回溯的过程 ,

所谓递推 , 在这道题中 , 我是这样递推的 : 要求 x^n 就必须知道 x^n-1

, 同理 , 要求 x^n-1 必须知道 x^n-2 , 所以我们可以一直递推下去 :

画板

一直递推到 x^0 , 到这里递推完成 ,接下来就是回溯了

所谓回溯 , 就是沿着之前走过的路回去 , 所谓来路便是去路 , 回溯也遵循着这样的佛法 ,

递推的终点 , 我们知道是 x^0 = 1, 既然知道了x^0是终点 , 那么沿着原路返回 , 就会遇到 :

要求 x^1 (只需在 x^0 上乘 x),

再遇到 x^2 (只需在 x^1 上乘 x) ,

最后依此类推

画板

我发现 , 递推是不断地分解问题为小的问题 ,直到最小可解决 , 而回溯是沿着来路解决问题 。

所以要判断一个题目是否可以使用递归 , 我们首先就要判断以下几点

  • 题目是否具有递归性 , 是否可递推? 是否可回溯 ?
  • 递推是否有终点 , 题目中的终点就是 , n === 0 的时候

面试官(内心 : 小伙子不错) : 你有时间复杂度更优的解法吗 ?

: 面试官有的 , 我还想到使用快速幂的方法 。我先说一下 ,我大体的思路 :

在我刚刚的代码中 , 时间复杂度是 O(n) , 所以为了优化 , 我应该想一个时间复杂度为 O(log(n)) 或者 O(根号 n) 的算法 , 而快速幂就是一种 O(log(n))的算法 , 我有两种实现方法 :

  • 在刚刚递归代码上采用指数折半的思想实现快速幂
  • 使用二进制的思路实现快速幂

为了与刚刚的递归的代码 , 产生联系 ,我先展示第一种写法 :

function h(x,n){
    if(n==0) return 1;
    t = h(x,Math.floor(n/2));
    if(n%2==0) return t*t;
    else return t*t*x;
}

我的思路是 : 对指数进行折半 , 比如在我们数学考试过程中 , 要我算 2^12 , 我会转化为

2^6 x 2^6 来算 ,因为 2^12 我一时间 算不出来 ,但 2^6 我会 。同理 , 代码的思想也是这样的 , 要求 x^n , 就先求 x ^(n/2) , 要求 x^(n/2) 就求 x^(n/4) , 依此类推 。(注意 n/2 向下取整), 我们看出这个也是具有递归性的 !

最后 , 对指数 n 讨论奇偶性

  • 指数 n 为偶数 ,只需求指数为 n/2 时的值 ,之后对这个值进行平方操作
  • 指数 n 为 奇 数 ,只需求指数为 n/2 时的值 , 该值平方后多乘一个底数x

面试官 : 请说说第二种思路

: 好的

function g(x, n) {
    let ans = 1;
    while (n > 0) {
        if (n & 1) {
            ans *= x;
        }
        x *= x;
        n >>= 1;
    }
    return ans;
}

面试官 : 行 , 这道题就到这里 , 我们再来看看另一道题


我 : 好 👀(内心 : 放马过来吧)

拷打中 ...