您的位置:首页 > 其它

快速幂,大数处理,递归优化

2016-08-03 14:22 441 查看

快速幂

例如求3^75

O(n)求法,直接将3连续乘75次

75的2进制 1001011

3^75 = 3^64 * 3^8 * 3^2 * 3^1 ,乘法次数将减少

对比程序

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
#include <set>
#include <map>
#include <ctime>

using namespace std;

const int INF = 0x7fffffff;
const int MIN = -INF - 1;

typedef long long LL;

// 时间复杂度 O(n)
LL f1(LL a, int n)
{
LL rs = 1;
for (int i = 0; i < n; i++)
{
rs *= a;
}
return rs;
}

// 时间复杂度 O(logn)
LL f2(LL x, int n)
{
int Max = 1000000007;
LL res = 1;
while (n>0)
{
if (n & 1) // 判断最低位是否是1
res = (res*x) % Max;
x = (x*x) % Max;// x变大
n >>= 1; // 右移一位(或者除以2)
}
return res;
}

int main()
{
int n = 1e7;
clock_t start, finish;
double totaltime;
start = clock();

cout << f2(1,n) << endl;

finish = clock();
//totaltime = (double)(finish - start) / CLOCKS_PER_SEC;
totaltime = (double)(finish - start) ;
cout << totaltime << endl;

//////////////////////////////
start = clock();

cout << f1(1, n) << endl;

finish = clock();
totaltime = (double)(finish - start);
cout << totaltime << endl;

return 0;
}


数值的整数次方

题目地址 (牛客网 剑指offer)

https://www.nowcoder.com/practice/1a834e5e3e1a4b7ba251417554e07c00?tpId=13&tqId=11165&tPage=1&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking

ac代码

class Solution {
public:
double Power(double base, int exponent) {
if(exponent == 0)
return 1;

bool flag = true;
if(exponent < 0)
{
flag = false;
exponent = - exponent;
}
bool flag2 = true;
if(base < 0){
flag2 = false;
base = - base;
}

double sign = 1.0;
if(flag2 == false && exponent % 2 == 1)
sign = -1.0;

double ans = 1;
double base2 = base;
int n = exponent;
while(n != 0)
{
int tmp = n & 1;
n = n >> 1;
if(tmp != 0)
ans = ans * base2;
base2 *= base2;
}
if(flag == false)
return sign * 1.0 / ans;
return sign * ans;
}
};


一般的规律(线性代数)

满足如下的线性关系表达式



都能写成 递推的矩阵相乘的情况,且矩阵的系数可以由前面的几项推出来,是确定的。

2阶情况



3阶情况



依次类推。。。

这样就可以根据前面几项 * 矩阵次幂 得到后面的项

例如



问题将转化为矩阵的乘幂运算,即快速幂问题,可以将时间复杂度优化为 O(logn)

372. Super Pow (leetcode)

题目地址

https://leetcode.com/problems/super-pow/

ac代码:

const int mod = 1337;

class Solution {
public:

// a^n % 1337 其中 n < 10
int npow(int a, int n)
{
a = a % mod;
vector<int> apn(11);
apn[0] = 1;
apn[1] = a;
for (int i = 2; i <= n; i++)
{
apn[i] = (apn[i - 1] * a) % mod;
}
return apn
;
}

int superPow(int a, vector<int>& b) {
a = a % mod;

int len = b.size();
if (len == 1)
{
return npow(a, b[0]);
}

int ans = 1;
int n = a;
for (int i = len - 1; i >= 0; i--){

if (b[i] > 0)
{
int btmp = npow(n, b[i]);
ans = (ans * btmp) % mod;
}
n = npow(n, 10); //n = n^10  即 a,a^10,a^100,a^1000
}

return ans;
}
};


50. Pow(x, n)

题目地址

https://leetcode.com/problems/powx-n/

ac代码如下,需要注意特殊数据,正负数等的处理

class Solution {
public:
double myPow(double x, int n) {
int INF = 0x7fffffff;
int MIN = -INF - 1;
if (n == 0)
return 1;

if (n == MIN) // 最大负数特殊处理
{
if (x < 0) // x是负数,也将变成正数
x = -x;
double ans = 1;
n = INF;
while (n != 0)
{
if ((n & 1) == 1)
ans *= x;
x = x*x;
n = n >> 1;// 带符号右移
}
ans *= x;
return 1.0 / ans;
}
bool flag = true;
if (n < 0)
{
n = -n;
flag = false;
}
int sign = 1;
if (x < 0)
{
x = -x;
if ((n & 1) == 1) // 奇数
sign = -1;
}

double ans = 1;
while (n != 0)
{
if ((n & 1) == 1)
ans *= x;
x = x*x;
n = n >> 1;// 带符号右移
}
if (flag)
return sign * ans;
else
return sign * (1.0 / ans);
}
};


斐波拉契加强版

http://www.nowcoder.com/practice/2393c500d43a4293aa7a662274aff4d1?tpId=49&tqId=29343&rp=4&ru=/ta/2016test&qru=/ta/2016test/question-ranking

对于斐波拉契经典问题,我们都非常熟悉,通过递推公式F(n) = F(n - 1) + F(n - 2),我们可以在线性时间内求出第n项F(n),现在考虑斐波拉契的加强版,我们要求的项数n的范围为int范围内的非负整数,请设计一个高效算法,计算第n项F(n)。第一个斐波拉契数为F(0) = 1。

给定一个非负整数,请返回斐波拉契数列的第n项,为了防止溢出,请将结果Mod 1000000007。

测试样例:

3

返回:2

12

返回 233

const int INF = 0x7fffffff;
const int MIN = -INF - 1;

const int N = 2;
const int Mod = 1000000007;

typedef struct matrix
{
long long data

;
matrix()
{
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
data[i][j] = 0;
}
}Ma;

// 矩阵相乘
Ma matrixMulti(Ma m1, Ma m2)
{
Ma rs;
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
rs.data[i][j] = 0;
for (int k = 0; k < N; k++)
{
rs.data[i][j] = (rs.data[i][j] + m1.data[i][k] * m2.data[k][j]) % Mod;
}
}
}
return rs;
}

// 矩阵的n次幂
Ma matrixN(Ma m, int n)
{
Ma rs;
for (int i = 0; i < N; i++) //rs成为单位矩阵
rs.data[i][i] = 1;

while (n > 0){
if (n & 1)
rs = matrixMulti(rs, m);
m = matrixMulti(m, m);
n >>= 1;
}

return rs;
}

class Fibonacci {
public:

int getNthNumber(int n) { //fabonacci加强版
// write code here
if (n == 0 || n == 1)
return 1;

Ma m; // fabonacci的二阶矩阵
m.data[0][0] = 1;
m.data[0][1] = 1;
m.data[1][0] = 1;
m.data[1][1] = 0;

// [fn fn-1] = [f1 f0] * matrix^(n-1)
Ma rs = matrixN(m, n - 1);

long long ans = 0;
for (int i = 0; i < N; i++)
ans = (ans + rs.data[i][0]) % Mod;

return ans;
}
};


3阶问题,同上

http://www.nowcoder.com/practice/f26698ae586b46428c87a5dbcdae272c?tpId=49&tqId=29345&rp=4&ru=/ta/2016test&qru=/ta/2016test/question-ranking

在农场中,奶牛家族是一个非常庞大的家族,对于家族中的母牛,从它出生那年算起,第三年便能成熟,成熟的母牛每年可以生出一只小母牛。即母牛从出生开始的第三年便能做妈妈。最开始农场只有一只母牛,它从第二年开始生小母牛。请设计一个高效算法,返回第n年的母牛总数,已知n的范围为int范围内的正整数。

给定一个正整数n,请返回第n年的母牛总数,为了防止溢出,请将结果Mod 1000000007。

测试样例:

6

返回:9

const int INF = 0x7fffffff;
const int MIN = -INF - 1;

const int N = 3;
const int Mod = 1000000007;

typedef struct matrix
{
long long data

;
matrix()
{
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
data[i][j] = 0;
}
}Ma;

// 矩阵相乘
Ma matrixMulti(Ma m1, Ma m2)
{
Ma rs;
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
rs.data[i][j] = 0;
for (int k = 0; k < N; k++)
{
rs.data[i][j] = (rs.data[i][j] + m1.data[i][k] * m2.data[k][j]) % Mod;
}
}
}
return rs;
}

// 矩阵的n次幂
Ma matrixN(Ma m, int n)
{
Ma rs;
for (int i = 0; i < N; i++) //rs成为单位矩阵
rs.data[i][i] = 1;

while (n > 0){
if (n & 1)
rs = matrixMulti(rs, m);
m = matrixMulti(m, m);
n >>= 1;
}

return rs;
}

class Cows {
public:

int countSum(int n) { //fabonacci加强版
// write code here
if (n <= 3)// f1 = 1 f2 = 2 f3 = 3
return n;

Ma m; // fabonacci的二阶矩阵
m.data[0][0] = 1;
m.data[0][1] = 1;
m.data[1][2] = 1;
m.data[2][0] = 1;

// fn = fn-1 + fn-3
// [fn fn-1 fn-2] = [f3 f2 f1] * matrix^(n-3)
Ma rs = matrixN(m, n - 3);

long long ans = 0;
for (int i = 0; i < N; i++)
ans = (ans + (3 - i) * rs.data[i][0]) % Mod;

return ans;
}
};


参考学习:

矩阵 快速幂

http://www.cnblogs.com/yan-boy/archive/2012/11/29/2795294.html

POJ-3070Fibonacci(矩阵快速幂求Fibonacci数列)

http://www.cnblogs.com/dongsheng/archive/2013/06/02/3114073.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐