LeetCode 372

题目:

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|。

时间: 2024-10-14 19:30:33

LeetCode 372的相关文章

LeetCode 第 372 题 (Super Pow)

LeetCode 第 372 题 (Super Pow) Your task is to calculate ab mod 1337 where a is a positive integer and b is an extremely large positive integer given in the form of an array. Example1: a = 2 b = [3] Result: 8 Example2: a = 2 b = [1,0] Result: 1024 这道题与

[LeetCode] 349 Intersection of Two Arrays &amp; 350 Intersection of Two Arrays II

这两道题都是求两个数组之间的重复元素,因此把它们放在一起. 原题地址: 349 Intersection of Two Arrays :https://leetcode.com/problems/intersection-of-two-arrays/description/ 350 Intersection of Two Arrays II:https://leetcode.com/problems/intersection-of-two-arrays-ii/description/ 题目&解法

LeetCode 442. Find All Duplicates in an Array (在数组中找到所有的重复项)

Given an array of integers, 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once. Find all the elements that appear twice in this array. Could you do it without extra space and in O(n) runtime? Example: Input: [4,3,2,7,

LeetCode OJ - Sum Root to Leaf Numbers

这道题也很简单,只要把二叉树按照宽度优先的策略遍历一遍,就可以解决问题,采用递归方法越是简单. 下面是AC代码: 1 /** 2 * Sum Root to Leaf Numbers 3 * 采用递归的方法,宽度遍历 4 */ 5 int result=0; 6 public int sumNumbers(TreeNode root){ 7 8 bFSearch(root,0); 9 return result; 10 } 11 private void bFSearch(TreeNode ro

LeetCode OJ - Longest Consecutive Sequence

这道题中要求时间复杂度为O(n),首先我们可以知道的是,如果先对数组排序再计算其最长连续序列的时间复杂度是O(nlogn),所以不能用排序的方法.我一开始想是不是应该用动态规划来解,发现其并不符合动态规划的特征.最后采用类似于LRU_Cache中出现的数据结构(集快速查询和顺序遍历两大优点于一身)来解决问题.具体来说其数据结构是HashMap<Integer,LNode>,key是数组中的元素,所有连续的元素可以通过LNode的next指针相连起来. 总体思路是,顺序遍历输入的数组元素,对每个

LeetCode OJ - Surrounded Regions

我觉得这道题和传统的用动规或者贪心等算法的题目不同.按照题目的意思,就是将被'X'围绕的'O'区域找出来,然后覆盖成'X'. 那问题就变成两个子问题: 1. 找到'O'区域,可能有多个区域,每个区域'O'都是相连的: 2. 判断'O'区域是否是被'X'包围. 我采用树的宽度遍历的方法,找到每一个'O'区域,并为每个区域设置一个value值,为0或者1,1表示是被'X'包围,0则表示不是.是否被'X'包围就是看'O'区域的边界是否是在2D数组的边界上. 下面是具体的AC代码: class Boar

LeetCode 10. Regular Expression Matching

https://leetcode.com/problems/regular-expression-matching/description/ Implement regular expression matching with support for '.' and '*'. '.' Matches any single character. '*' Matches zero or more of the preceding element. The matching should cover

(leetcode题解)Pascal&#39;s Triangle

Pascal's Triangle  Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5,Return [ [1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1] ] 题意实现一个杨辉三角. 这道题只要注意了边界条件应该很好实现出来,C++实现如下 vector<vector<int>> generate(int

[LeetCode]Count Primes

题目:Count Primes 统计1-n的素数的个数. 思路1: 通常的思想就是遍历(0,n)范围内的所有数,对每个数i再遍历(0,sqrt(i)),每个除一遍来判断是否为素数,这样时间复杂度为O(n*sqrt(n)). 具体实现不在贴代码,过程很简单,两重循环就可以解决.但是效率很差,n较大时甚至会花几分钟才能跑完. 思路2: 用埃拉特斯特尼筛法的方法来求素数,时间复杂度可以达到O(nloglogn). 首先开一个大小为n的数组prime[],从2开始循环,找到一个质数后开始筛选出所有非素数