码迷,mamicode.com
首页 > 其他好文 > 详细

LeetCode 372

时间:2016-07-20 19:24:23      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:

题目:

Your task is to calculate a^b mod 1337 where a is a positive integer and b is an extremely large positive integer given in the form of an array.

求a的b次方mod 1337,其中b是一个extremely large的数,以至于需要用整数数组来存储。

引理:(a × b)mod M = ((a mod M) * (b mod M)) mod M

证明:

若 a = x·M + m, b = y·M + n

(a × b) mod M = (xyMM + myM + nxM + mn) mod M

其中 xyMM, myM, nxM 均能被M整除,故

(a × b) mod M = mn mod M

解题思路:

百度来基本解题思路均为二分,将b作为数字处理。相关链接:http://blog.csdn.net/mebiuw/article/details/51853673

可能我的思路比较特殊,当然方法也比较复杂,但是理论上复杂度应该更低。

举个例子,若b是一个5位数,b = A*1000 + B*1000 + C*100  + D*10 + E

注意到,a^b = a^(A*10000 + B*1000 + C*100  + D*10 + E) = (a^10000)^A + (a^1000)^B + (a^100)^C + (a^10)^D + (a^1)^E

可以利用一个与b等长的数组把a^(10^n)存储下来,之后每次可以直接拿过来用。因为 a^n mod M = ((a^(n/2) mod M) * (a^(n/2) mod M)) mod M, 所以这里可以使用上述引理,执行二分策略。

而对于每一个 a^(10^i)^bi, 又可以看做 ai ^ bi, 这里依旧可以利用引理进行二分。

AC代码如下:

public final int MOD = 1337;
    public int modProd(int x, int y){
        return ((x%MOD)*(y%MOD))%MOD;
    }
    public int pow(int a, int b){
        //    return (a^b)%MOD
        if (b == 0) return 1;
        if (b == 1) return a%MOD;
        int m = pow(a, b/2);
        if (b%2 == 1){
            return modProd(a, m*m);
        }else{
            return modProd(m, m);
        }
    }
    public int superPow(int a, int[] b) {
        int[] mpow = new int[b.length];
        int i, j;
        for (i = 0, j = b.length-1; i < j; i++, j--){
            //    b 中高低位交换,便于后续编码
            b[i] = b[i] ^ b[j];
            b[j] = b[i] ^ b[j];
            b[i] = b[i] ^ b[j];
        }
        mpow[0] = a%MOD;
        for (i = 1; i< b.length; i++){
            //    预处理,存储 (a^(10^i)) mod M
            //    预处理过程中,对于 a^(10^i)看做 a^(10^(i-1)) ^ 10, 这样每次只需要运行 log 10 次
            mpow[i] = pow(mpow[i-1], 10);
        }
        int res = 1;
        for (i = 0; i< b.length; i++){
            //    对每一位 bi 计算 a^(bi*(10^i))
            res = modProd(res, pow(mpow[i], b[i]));
        }
        
        return res;
    }

预处理阶段,计算 a^(10^i) mod M, 由于每次是提取前一次的结果作为基数,故每次需要4次,预处理的时间复杂度为 4·|b|,其中|b|为字符串b的长度。

运行阶段,每次运行也是最多4次,故其复杂度为 4·|b|。

整个程序运行复杂度为 O(8·|b|)

而对于其他解法,其每次二分均需要对b进行一次处理,故其复杂度为 O(|b|×log(Valueof(b))),其中Valueof(b)表示数组b所代表的值,它将远远大于 |b|。

 

LeetCode 372

标签:

原文地址:http://www.cnblogs.com/flowingcloud/p/5689422.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!