AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

斐波那契数列优化算法

作者: 作者的头像   wuog ,  2019-09-20 21:43:38 ,  所有人可见 ,  阅读 2027


14


11

概述

你能写出多少个斐波那契数列的解法?递归?
如果有一个问题要你去求一个斐波那契数列的前n项乘积(n<=99989)!!!
怎么办?
你还去递归求解,然后再去算乘积!那你的有可能就TLE了,所以接下来给大家推荐几个好的算法。

C(C++函数)代码

递归算法实现
uint64_t fibonacci1(unsigned int n) {
    if (n == 0) return 0;
    if (n <= 2) return 1;
    return fibonacci1(n - 1) + fibonacci1(n - 2);
}
循环迭代算法实现
uint64_t fibonacci2(unsigned int n) {
    if (n == 0) return 0;
    if (n == 1 || n == 2) return 1;
    uint64_t f1 = 1, f2 = 1, fn;
    for (unsigned int i = 3; i <= n; i++) {
        fn = f1 + f2;
        f1 = f2;
        f2 = fn;
    }
    return fn;
}
原始矩阵算法实现

uint64_t fibonacci3(unsigned int n) {
    uint64_t m[2][2] = { 1,1,1,0 }; // 1次矩阵
    uint64_t result[][2] = { 1,0,0,1 }; // 单位矩阵
    uint64_t temp[2][2];
    // 计算n次矩阵
    for (unsigned int i = 1; i <= n; i++) {
        temp[0][0] = result[0][0] * m[0][0] + result[0][1] * m[1][0];
        temp[0][1] = result[0][0] * m[0][1] + result[0][1] * m[1][1];
        temp[1][0] = result[1][0] * m[0][0] + result[1][1] * m[1][0];
        temp[1][1] = result[1][0] * m[0][1] + result[1][1] * m[1][1];
        memcpy(result, temp, sizeof(uint64_t) * 4);
    }
    return result[1][0] * 1;
}
矩阵快速幂优化算法

uint64_t fibonacci4(unsigned int n) {
    uint64_t m[2][2] = { 1,1,1,0 }; // 1次矩阵
    uint64_t result[][2] = { 1,0,0,1 }; // 单位矩阵
    uint64_t temp[2][2];
    while (n) {
        if (n & 1) {
            temp[0][0] = result[0][0] * m[0][0] + result[0][1] * m[1][0];
            temp[0][1] = result[0][0] * m[0][1] + result[0][1] * m[1][1];
            temp[1][0] = result[1][0] * m[0][0] + result[1][1] * m[1][0];
            temp[1][1] = result[1][0] * m[0][1] + result[1][1] * m[1][1];
            memcpy(result, temp, sizeof(uint64_t) * 4);
        }
        // 2、4、8...次幂矩阵
        temp[0][0] = m[0][0] * m[0][0] + m[0][1] * m[1][0];
        temp[0][1] = m[0][0] * m[0][1] + m[0][1] * m[1][1];
        temp[1][0] = m[1][0] * m[0][0] + m[1][1] * m[1][0];
        temp[1][1] = m[1][0] * m[0][1] + m[1][1] * m[1][1];
        memcpy(m, temp, sizeof(uint64_t) * 4);
        n >>= 1;
    }
    return result[1][0] * 1;
}
矩阵快速幂查表算法
uint64_t fibonacci5(unsigned int n) {
    const static uint64_t cache[][2][2] = {
        { 1, 0, 0, 1 },// 0次幂(无用)
        { 1, 1, 1, 0 },// 1次幂(2^0,1)
        { 2, 1, 1, 1 },// 2次幂(2^1,2)
        { 5, 3, 3, 2 },// 4次幂(2^2,3)
        { 34, 21 ,21, 13 },// 8次幂(2^3,4)
        { 1597, 987, 987 ,610 },// 16次幂(2^4,5)
        { 3524578, 2178309, 2178309, 1346269 },// 32次幂(2^5,4)
        { 17167680177565, 10610209857723, 10610209857723, 6557470319842 },//64次幂(2^6,5)
        { 8102862946581596898, 18154666814248790725, 18154666814248790725, 8394940206042357789 }//128次幂(2^7,6)
    };
    uint64_t result[][2] = { 1, 0, 0, 1 }; // 单位矩阵
    uint64_t temp[2][2];
    int bit_pos = 1;
    while (n) {
        if (n & 1) {
            temp[0][0] = result[0][0] * cache[bit_pos][0][0] + result[0][1] * cache[bit_pos][1][0];
            temp[0][1] = result[0][0] * cache[bit_pos][0][1] + result[0][1] * cache[bit_pos][1][1];
            temp[1][0] = result[1][0] * cache[bit_pos][0][0] + result[1][1] * cache[bit_pos][1][0];
            temp[1][1] = result[1][0] * cache[bit_pos][0][1] + result[1][1] * cache[bit_pos][1][1];
            memcpy(result, temp, sizeof(uint64_t) * 4);
        }
        n >>= 1;
        bit_pos++;
    }
    // result[1][0] * 1 + result[1][1] * 0;
    return result[1][0] * 1;
}

通项公式直接求解
uint64_t fibonacci6(unsigned int n) {
    const double sqrt5 = 2.2360679774997896964091736687313;
    const double a = (sqrt5 + 1) / 2;
    const double b = (1 - sqrt5) / 2;
    const double sqrt1_5 = 1 / sqrt5;

    return (uint64_t)((pow(a, n) - pow(b, n))*sqrt1_5);
}
矩阵求解
void power_matrix(uint64_t m[][2], unsigned int exp) {
    uint64_t result[][2] = { 1,0,0,1 }; // 单位矩阵
    uint64_t temp[2][2];
    // 计算n次矩阵
    for (unsigned int i = 1; i <= exp; i++) {
        temp[0][0] = result[0][0] * m[0][0] + result[0][1] * m[1][0];
        temp[0][1] = result[0][0] * m[0][1] + result[0][1] * m[1][1];
        temp[1][0] = result[1][0] * m[0][0] + result[1][1] * m[1][0];
        temp[1][1] = result[1][0] * m[0][1] + result[1][1] * m[1][1];
        memcpy(result, temp, sizeof(uint64_t) * 4);
    }
    memcpy(m, result, sizeof(uint64_t) * 4);
}
void generate_matrix() {
    uint64_t m[2][2] = { 1,1,1,0 }; // 1次矩阵
    uint64_t temp[2][2];
    for (int i = 0; i < 8; i++) {
        memcpy(temp, m, 4 * sizeof(uint64_t));
        printf("{");
        power_matrix(temp, 1 << i);
        for (int j = 0; j < 2; j++) {
            for (int k = 0; k < 2; k++) {
                printf("%llu, ", temp[j][k]);
            }
        }
        printf("},\n");
    }
}
整数乘法的实现(使用加法和移位操作)
int quick_multi(int a, int b) {
    int bits, factor;
    if (a < b) {
        bits = a;
        factor = b;
    }
    else {
        bits = b;
        factor = a;
    }

    int result = 0;
    while (bits) {
        if (bits & 1)
            result += factor;
        bits >>= 1; // 除2
        factor <<= 1; // 乘2
    }
    return result;
}
整数快速幂运算
int quick_pow(int base, int exp) {
    int result = 1;
    while (exp) {
        if (exp & 1)
            result *= base;
        exp >>= 1;
        base <<= 1; 
    }
    return result;
}

比较测试

/* 计算时间间隔 */

double duration(struct timespec *end, struct timespec *start) {
    double d_sec = difftime(end->tv_sec, start->tv_sec);
    long d_nsec = end->tv_nsec - start->tv_nsec;
    return (d_sec*10e9 + d_nsec);
}

/* 算法测试 */
void compare_and_test() {
    typedef uint64_t(*PFUNC)(unsigned int n);
    PFUNC pFuncs[] = { fibonacci2 ,fibonacci3, fibonacci4, fibonacci5, fibonacci6 };
    struct timespec start, end;
    for (int j = 0; j < sizeof(pFuncs) / sizeof(PFUNC); j++) {
        timespec_get(&start, TIME_UTC);
        // 93项后会发生溢出,这里测试计算时间,所以不关心溢出问题
        for (int i = 0; i < 95; i++) {
#           ifdef NDEBUG
            (*pFuncs[j])(i);
#           else
            printf("%llu ", (*pFuncs[j])(i));
#           endif
        }
        timespec_get(&end, TIME_UTC);
        printf("\t duration: %lf nanosecond\n", duration(&end, &start));
    }
}

void main() {
    compare_and_test();//比较时间
    generate_matrix();//调用
}

java

递归
public static long f1(int n) {
    if (n <= 0) {
        throw new RuntimeException("输入参数小于1");
    }
    if (n == 1 || n == 2) {
        return 1;
    }
    return f1(n - 2) + f1(n - 1);
}
递归2(HashMap)
static HashMap<Integer, Long> map = new HashMap<>();

public static long f2(int n) {
    if (n <= 0) {
        throw new RuntimeException("输入参数小于1");
    }
    if (n == 1 || n == 2) {
        return 1;
    }
    if (!map.containsKey(n)) {
        map.put(n, f2(n - 2) + f2(n - 1));
    }
    return map.get(n);
}
递归3(数组)
static long[] mArray = new long[8000 + 1];
public static long f3(int n) {
    if (n <= 0) {
        throw new RuntimeException("输入参数小于1");
    }
    if (n == 1 || n == 2) {
        return mArray[n] = 1;
    }
    if (mArray[n] == 0) {
        mArray[n] = f3(n - 1) + f3(n - 2);
    }
    return mArray[n];
}
公式
public static long f6(int n) {
    double result = 0;
    double temp = Math.sqrt(5.0);
    result = (Math.pow((1 + temp) / 2, n) - Math.pow((1 - temp) / 2, n)) / temp;
    return (long) result;
}
矩阵
static long[][] initMatirx = {{1, 1}, {1, 0}};
public static long f7(int n) {
    if (n <= 0) {
        throw new RuntimeException("输入参数小于1");
    }
    if (n == 1 || n == 2) {
        return 1;
    }
    long[][] tem = initMatirx;
    for (int i = 1; i < n - 2; i++) {
        tem = matirxMulti(tem, initMatirx);
    }
    return tem[0][0] + tem[1][0];
}
private static long[][] matirxMulti(long[][] a, long[][] b) {
    long[][] temp = new long[2][2];
    temp[0][0] = a[0][0] * b[0][0] + a[0][1] * b[1][0];
    temp[0][1] = a[0][0] * b[0][1] + a[0][1] * b[1][1];
    temp[1][0] = a[1][0] * b[0][0] + a[1][1] * b[1][0];
    temp[1][1] = a[1][0] * b[0][1] + a[1][1] * b[1][1];
    return temp;
}

矩阵加快速幂
static long[][] initMatirx = {{1, 1}, {1, 0}};
static long[][] unitMatrix = {{1, 0}, {0, 1}};//单位矩阵
public static long f8(int n) {
    if (n <= 0) {
        throw new RuntimeException("输入参数小于1");
    }
    if (n == 1 || n == 2) {
        return 1;
    }
    long[][] result = unitMatrix;
    long[][] tem = initMatirx;
    int m = n - 2;
    while (m != 0) {
        if ((m & 1) == 1) {
            result = matirxMulti(tem, result);
        }
        tem = matirxMulti(tem, tem);
        m >>= 1;
    }
    return result[0][0] + result[1][0];
}

顺序递推
public static long f5(int n) {
        if (n <= 0) {
            throw new RuntimeException("输入参数小于1");
        }
        if (n == 1 || n == 2) {
            return 1;
        }
        long a = 1;
        long b = 1;
        long c = 0;
        for (int i = 3; i <= n; i++) {
            c = a + b;
            a = b;
            b = c;
        }
        return c;
    }

看下来


----->【 详细解释 】

9 评论


用户头像
cht   2020-09-12 20:19         踩      回复

流批


用户头像
李大戮   2019-11-01 01:20         踩      回复

tql!


用户头像
robot_1   2019-10-01 19:58         踩      回复

tql!今天我们就考了一个类似的题qaq


用户头像
Sophon   2019-09-24 19:06         踩      回复

优秀


用户头像
Zhao001   2019-09-22 17:34         踩      回复

你还是太强了~~


用户头像
bigbrox   2019-09-20 21:59         踩      回复

nb

用户头像
wuog   2019-09-24 20:25         踩      回复

orz ..


用户头像
墨染空   2019-09-20 21:47         踩      回复

您tql

用户头像
wuog   2019-09-24 20:25         踩      回复

小白。。。hh


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息