今天刷lintcode的时候发现了一道简单的题目,本来没留意很快就写完了,但是提交的时候发现有些测试用例通不过,总是超时,于是明白这道题应该在改进时间复杂度上下功夫,因此总结如下。
题目描述如下:
Calculate the an % b where a, b and n are all 32bit integers.
For 231 % 3 = 2
For 1001000 % 1000 = 0
未考虑时间复杂度的算法:
思想:
由于a, b, n都是int型,要考虑溢出的情况,因此只需要在循环内部每次乘法运算的时候都进行mod运算即可。
代码:
class Solution {
public:
/**
* @param a: A 32bit integer
* @param b: A 32bit integer
* @param n: A 32bit integer
* @return: An integer
*/
int fastPower(int a, int b, int n) {
long long res = 1;
if(n==0)
return 1%b;
for(int i=0; i<n; i++)
res = (res*a)%b;
return res;
}
};
如果按照这种写法,可以运行,但是当n比较大的时候,无法通过测试用例,时间复杂度为O(n)。
考虑时间复杂度的算法:
思想:
需要提高时间复杂度,我想起了学习密码学的时候求解幂取模运算时候使用的方法。假如求 x ^ n 次方,首先将n转化为2进制的形式,然后我们可以把 n 表示为 2^k1 + 2k2 + 2^k3....,这样所有数都可以用前式来表示。那么 x^n = x^2^k1 * x^2^k2 * x^2^k3.....那么就可以利用二进制来加快计算速度了。
假如 x^19 , 22转化为二进制为 10011, 即 x^19 = x^16 * x^2 * x^1;
这个时候就已经很清晰了。此时的时间复杂度为O(log(n)),可以通过题库的测试用例。
代码:
class Solution {
public:
/**
* @param a: A 32bit integer
* @param b: A 32bit integer
* @param n: A 32bit integer
* @return: An integer
*/
int fastPower(int a, int b, int n) {
int res = 1;
long long tmp = a;
if(n==0)
return 1%b;
while(n>0){
if(n&0x1)
res = (res*tmp)%b;
tmp = (tmp*tmp)%b;
n >>= 1;
}
return res;
}
};
总结:
很多看似很简单的题目其实需要多思考,和平时学到的东西联系起来,即使第一种方法能通过测试用例,也最好不要使用,因为这样会带来不必要的时间开销。