快速幂,大数处理,递归优化
2016-08-03 14:22
441 查看
快速幂
例如求3^75O(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-rankingac代码
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
相关文章推荐
- MySQL数据库优化处理实现千万级快速分页分析
- 如何优化Mysql千万级快速分页,limit优化快速分页,MySQL处理千万级数据查询的优化方案!(zz)
- ZOJ -- 2317(矩阵快速幂 + 大数简单处理)
- 快速排序的底层递归优化和针对基本有序序列的优化
- 图形图像处理-之-高质量的快速的图像缩放 上篇 近邻取样插值和其速度优化
- 图形图像处理-之-高质量的快速的图像缩放 上篇 近邻取样插值和其速度优化
- 如何优化Mysql千万级快速分页,limit优化快速分页,MySQL处理千万级数据查询的优化方案!
- 【HDU4919】递推java大数 递归优化
- 如何优化Mysql千万级快速分页,limit优化快速分页,MySQL处理千万级数据查询的优化方案!(zz)
- 图形图像处理-之-高质量的快速的图像缩放 补充 使用SSE2优化
- POJ 1519 求大数各位上数字之和 大数处理 递归
- 图像处理之优化---任意半径局部直方图类算法在PC中快速实现的框架
- 图形图像处理-之-高质量的快速的图像缩放 上篇 近邻取样插值和其速度优化
- 图形图像处理-之-高质量的快速的图像缩放 补充 使用SSE2优化
- POJ 1519 求大数各位上数字之和 大数处理 递归
- 图形图像处理-之-高质量的快速的图像缩放 补充 使用SSE2优化
- 快速幂取余(大数运算/算法优化)
- MySQL数据库优化处理实现千万级快速分页分析,来看下吧。
- 如何优化Mysql千万级快速分页,limit优化快速分页,MySQL处理千万级数据查询的优化方案!
- (转)图形图像处理-之-高质量的快速的图像缩放 上篇 近邻取样插值和其速度优化