• 【初识算法】-Day1


    14天阅读挑战赛
    努力是为了不平庸~
    算法学习有些时候是枯燥的,这一次,让我们先人一步,趣学算法!欢迎记录下你的那些努力时刻(算法学习知识点/算法题解/遇到的算法bug/等等),在分享的同时加深对于算法的理解,同时吸收他人的奇思妙想,一起见证技术er的成长~

    不会算法的程序员不是合格程序员,于是我开始学习算法

    算法知识点

    斐波那契数列

    算法题目描述

    写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:

    F(0) = 0,   F(1) = 1
    F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
    斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。

    答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

    做题思路

    方法一:

    递归是会超时的,所以用动态规划

    斐波那契数的边界条件是 F(0)=0F(0)=0 和 F(1)=1F(1)=1。当 n>1n>1 时,每一项的和都等于前两项的和,因此有如下递推关系:

    F(n)=F(n-1)+F(n-2)
    F(n)=F(n−1)+F(n−2)

    由于斐波那契数存在递推关系,因此可以使用动态规划求解。动态规划的状态转移方程即为上述递推关系,边界条件为 F(0)F(0) 和 F(1)F(1)。

    根据状态转移方程和边界条件,可以得到时间复杂度和空间复杂度都是 O(n)O(n) 的实现。由于 F(n)F(n) 只和 F(n-1)F(n−1) 与 F(n-2)F(n−2) 有关,因此可以使用「滚动数组思想」把空间复杂度优化成 O(1)。计算过程中,答案需要取模 1e9+7。

    方法二:矩阵快速幂
    方法一的时间复杂度是 O(n)O(n)。使用矩阵快速幂的方法可以降低时间复杂度。

    方法一

    javascript:

    1. var fib = function(n) {
    2.     const MOD = 1000000007;
    3.     if (n < 2) {
    4.         return n;
    5.     }
    6.     let p = 0, q = 0, r = 1;
    7.     for (let i = 2; i <= n; ++i) {
    8.         p = q; 
    9.         q = r; 
    10.         r = (p + q) % MOD;
    11.     }
    12.     return r;
    13. };

    java:

    1. class Solution {
    2. public int fib(int n) {
    3. final int MOD = 1000000007;
    4. if (n < 2) {
    5. return n;
    6. }
    7. int p = 0, q = 0, r = 1;
    8. for (int i = 2; i <= n; ++i) {
    9. p = q;
    10. q = r;
    11. r = (p + q) % MOD;
    12. }
    13. return r;
    14. }
    15. }

    C#:

    1. public class Solution {
    2. public int Fib(int n) {
    3. const int MOD = 1000000007;
    4. if (n < 2) {
    5. return n;
    6. }
    7. int p = 0, q = 0, r = 1;
    8. for (int i = 2; i <= n; ++i) {
    9. p = q;
    10. q = r;
    11. r = (p + q) % MOD;
    12. }
    13. return r;
    14. }
    15. }

    动态规划的算法复杂度

    • 时间复杂度:O(n)。

    • 空间复杂度:O(1)。

    方法二

    js:

    1. var fib = function(n) {
    2. if (n < 2) {
    3. return n;
    4. }
    5. const q = [[1, 1], [1, 0]];
    6. const res = pow(q, n - 1);
    7. return res[0][0];
    8. };
    9. const pow = (a, n) => {
    10. let ret = [[1, 0], [0, 1]];
    11. while (n > 0) {
    12. if ((n & 1) === 1) {
    13. ret = multiply(ret, a);
    14. }
    15. n >>= 1;
    16. a = multiply(a, a);
    17. }
    18. return ret;
    19. }
    20. const multiply = (a, b) => {
    21. const c = new Array(2).fill(0).map(() => new Array(2).fill(0));
    22. for (let i = 0; i < 2; i++) {
    23. for (let j = 0; j < 2; j++) {
    24. c[i][j] = (BigInt(a[i][0]) * BigInt(b[0][j]) + BigInt(a[i][1]) * BigInt(b[1][j])) % BigInt(1000000007);
    25. }
    26. }
    27. return c;
    28. }

    java:

    1. class Solution {
    2. static final int MOD = 1000000007;
    3. public int fib(int n) {
    4. if (n < 2) {
    5. return n;
    6. }
    7. int[][] q = {{1, 1}, {1, 0}};
    8. int[][] res = pow(q, n - 1);
    9. return res[0][0];
    10. }
    11. public int[][] pow(int[][] a, int n) {
    12. int[][] ret = {{1, 0}, {0, 1}};
    13. while (n > 0) {
    14. if ((n & 1) == 1) {
    15. ret = multiply(ret, a);
    16. }
    17. n >>= 1;
    18. a = multiply(a, a);
    19. }
    20. return ret;
    21. }
    22. public int[][] multiply(int[][] a, int[][] b) {
    23. int[][] c = new int[2][2];
    24. for (int i = 0; i < 2; i++) {
    25. for (int j = 0; j < 2; j++) {
    26. c[i][j] = (int) (((long) a[i][0] * b[0][j] + (long) a[i][1] * b[1][j]) % MOD);
    27. }
    28. }
    29. return c;
    30. }
    31. }

    C#:

    1. public class Solution {
    2. const int MOD = 1000000007;
    3. public int Fib(int n) {
    4. if (n < 2) {
    5. return n;
    6. }
    7. int[,] q = {{1, 1}, {1, 0}};
    8. int[,] res = Pow(q, n - 1);
    9. return res[0, 0];
    10. }
    11. public int[,] Pow(int[,] a, int n) {
    12. int[,] ret = {{1, 0}, {0, 1}};
    13. while (n > 0) {
    14. if ((n & 1) == 1) {
    15. ret = Multiply(ret, a);
    16. }
    17. n >>= 1;
    18. a = Multiply(a, a);
    19. }
    20. return ret;
    21. }
    22. public int[,] Multiply(int[,] a, int[,] b) {
    23. int[,] c = new int[2, 2];
    24. for (int i = 0; i < 2; i++) {
    25. for (int j = 0; j < 2; j++) {
    26. c[i, j] = (int) (((long) a[i, 0] * b[0, j] + (long) a[i, 1] * b[1, j]) % MOD);
    27. }
    28. }
    29. return c;
    30. }
    31. }

    矩阵快速幂的算法复杂度

    • 时间复杂度:O(logn)。

    • 空间复杂度:O(1)。

    读书笔记

    我的算法不太行,我的数学也不太行。还有很大的进步空间哈哈哈哈

  • 相关阅读:
    川渝杯2022个人决赛部分wp
    Appium开发
    Jetty各版本历史
    代码随想录算法训练营第三天 | leetcode203、707、206
    面试算法 三个数的最大乘积整型数组nums,在数组中找出由三个数字组成的最大乘积,并输出这个乘积。乘积不会越界
    Python的高级用法:命名元组
    编译opencv.js
    Android JetPack Compose+Room----实现搜索记录功能
    Windows无法访问指定设备、路径或文件怎么办?
    在Ubuntu或linux中为coreutils工具包的cp和mv命令添加进度条
  • 原文地址:https://blog.csdn.net/weixin_55355282/article/details/127457082