Classical algorithm of dynamic programming (Fibonacci sequence)

Applicable scene:

The sub-problems are of the same nature as the original problem

The sub-problems are interrelated (different from the divide and conquer algorithm)

Seeking the optimal solution, the core is exhaustive

Dynamic planning features:

  1. Overlapping subproblems
  2. State transition equation (the most critical)
  3. Optimal substructure

Dynamic program problem-solving framework

  1. base_case
  2. Exhaustive state
  3. State transition

Classic case 1: Fibonacci sequence

f[1] = 1
f[2] = 2
f[n] = f[n-1]+f[n-2] // state transition equation

The Fibonacci number sequence is not an authentic dynamic programming problem, at least not a problem of seeking an optimal solution.

Code implementation-recursion (violent recursion)

/*
    斐波那契数列
    暴力递归
*/
#include <stdio.h>
#include <stdlib.h>

int fib(int n) {
    // base_case
    if (n ==1 || n ==2) {
        return n;
    }
    // 递归调用
    return fib(n - 1) + fib(n - 2);
}

int main() {
    int n = 200;
    printf("fib(%d) = %d\n", n, fib(n));
    return 0;
} 

The recursion method is too inefficient. There are a lot of repetitive calculations, the time complexity is O(2^n), and it is time-consuming.

Code implementation-recursive method (top-down/with memo)

Recurse first from top to bottom, and then backtrack from bottom to top.

/*
    斐波那契数列
    带备忘录的递归
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int helper(int *memo, int n) {
    // base_case
    if (n ==1 || n ==2) {
        return n;
    }
    // 备忘录查询
    if (memo[n] != 0) return memo[n];

    memo[n] = helper(memo, n - 1) + helper(memo, n - 2);
    return memo[n];
}

int fib(int n) {
    // 备忘录初始化
    int *memo = new int[n + 1];
    memset(memo, 0, n+1);
    // 进行带备忘录的递归
    return helper(memo, n);
}

int main() {
    int n = 50;
    printf("fib(%d) = %d\n", n, fib(n));
    return 0;
} 

Now every node is only calculated once, so the time complexity is O(n).
Due to an additional new memory allocation. So there is one more space expense, so the space complexity is O(n).
The recursive solution with memo is space for time

Code implementation-iterative method (bottom-up)

/*
    斐波那契数列
    带备忘录的递归
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int helper(int *memo, int n) {
    // base_case
    if (n ==1 || n ==2) {
        return n;
    }
    // 备忘录查询
    if (memo[n] != 0) return memo[n];

    memo[n] = helper(memo, n - 1) + helper(memo, n - 2);
    return memo[n];
}

int fib(int n) {
    // 备忘录初始化
    int *memo = new int[n + 1];
    memset(memo, 0, n+1);
    // 进行带备忘录的递归
    return helper(memo, n);
}

int main() {
    int n = 50;
    printf("fib(%d) = %d\n", n, fib(n));
    return 0;
} 

 

Guess you like

Origin blog.csdn.net/weixin_44937328/article/details/115344896