算法学习笔记六 打表法

打表法

何为打表?

就是先用程序把所有答案都算出来,存进文件里,或者输出在黑框里(这个计算过程是不用考虑时间内存大小的),然后把文件里的答案做成数组,之后根据下标输出对应答案即可。利用这种方法,程序运行时间复杂度永远是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] << ",";
        //打个逗号方便之后打表 
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值