打表法
何为打表?
就是先用程序把所有答案都算出来,存进文件里,或者输出在黑框里(这个计算过程是不用考虑时间内存大小的),然后把文件里的答案做成数组,之后根据下标输出对应答案即可。利用这种方法,程序运行时间复杂度永远是O(n)。
例题:斐波那契数列
还是笔记五中的求斐波那契数列的问题,范围是n<=48:
先运行程序,把斐波那契数列的每一项都算出来,并输出到框里:
【这里用的就是最基本的做法,在之前我们也验证过了,n>48的时候就会超时了】
#include <cstdio>
using namespace std;
#define ll long long
//一定要开long long,第47位就爆int了
int main() {
printf("1,1,"); //先输出第一个数和第二个数
ll f[50];
f[1] = f[2] = 1;
for (int i = 3; i <= 48; i++)
f[i] = f[i - 1] + f[i - 2];
//斐波那契递推公式f[n]=f[n-1]+f[n-2]
for (int i = 3; i <= 48; ++i) {
printf("%lld,", f[i]);
//输出要采用long long的格式化输出,不然就凉凉
//打个逗号方便之后打表
}
}
然后我们得到:
然后再重新写一个代码:
#include <cstdio>
using namespace std;
#define ll long long
int main() {
ll f[50] = { 1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102334155,165580141,267914296,433494437,701408733,1134903170,1836311903,2971215073,4807526976 };
int n;
scanf_s("%d", &n);
printf("%lld", f[n-1]);
}
非常easy,就可以根据n得到对应的数啦!
【这里采用的是long long,大约会在n=90时发生溢出,所以在n小于90的时候采用这个方法是没有问题的。】
升级一点点
把高精放进打表里来,用字符串存放数据,可以没有ll的束缚。
【可以到2^10】
#include <cstdio>
#include<string>
#include<string.h>
#include<iostream>
using namespace std;
#define ll long long
//一定要开long long,第47位就爆int了
const int mod = 1000000007;
//高精度加法
//只能是两个正数相加
string add(string str1, string str2)//高精度加法
{
string str;
int len1 = str1.length();
int len2 = str2.length();
//前面补0,弄成长度相同
if (len1 < len2)
{
for (int i = 1; i <= len2 - len1; i++)
str1 = "0" + str1; //在前面添0哦
}
else
{
for (int i = 1; i <= len1 - len2; i++)
str2 = "0" + str2;
}
len1 = str1.length(); //现在是一样的
int cf = 0; //进位标志,最开始是0
int temp; //存每一次计算后的个位
for (int i = len1 - 1; i >= 0; i--) //从最后一位开始做加法
{
temp = str1[i] - '0' + str2[i] - '0' + cf; //这里是强制转换,得到的是两数同一位的和+cf
cf = temp / 10; //前一位的进位标志,如果cf>10,说明要进位呀
temp %= 10; //进位之后的两数和的个位
str = char(temp + '0') + str; //再一次强制转换,把刚刚算出来的个位存进str里
}
if (cf != 0) str = char(cf + '0') + str; //全部循环完之后,查看最前面一位的进位标志是否为1
return str; //返回结果,是string格式的
}
int main() {
printf("1,1,"); //先输出第一个数和第二个数
const int N = 1024;
string f[N+5];
f[1] = f[2] = "1";
for (int i = 3; i <= N; i++)
{
string stmp;
stmp = add(f[i - 1], f[i - 2]);
ll tmp = 0;
int len = stmp.length();
for (int j = 0; j <= len-1; j++)
{
int g = int(stmp[j] - '0');
tmp = tmp * 10 + g;
}
tmp = tmp % mod;
f[i] = std::to_string(tmp);
}
//斐波那契递推公式f[n]=f[n-1]+f[n-2]
for (int i = 3; i <= N; ++i) {
cout << f[i] << ",";
//打个逗号方便之后打表
}
}