Summary of algorithm and question types of dynamic programming

Dynamic Programming (DP)

It is understood that a large problem is divided into a pile of small problems, and these small problems will not be calculated repeatedly.

Dynamic programming is divided into top-down (recursive time complexity, taking Fibonacci number as an example, n^h-1, space complexity as n) and bottom-up (high efficiency, optimal solution, generally one-dimensional dp is optimized by rolling array).

Problem solving steps of dynamic programming:

1: State definition (defining dp array) 2: transfer equation (the split problem determines the bottom-up transfer equation of dp array) 3: initial state (determines the dp value at the bottom at the beginning): 4: return value (which value of dp array is the final result)

Take Fibonacci number as an example

Sword finger Offer 10- I. Fibonacci sequence

If you use the top-down method to solve the problem, it is recursion


def fib(n):
    if n == 1 or n == 2:
        return 1
    return fib(n - 1) + fib(n - 2)

  Picture transferred from Force buckle

Because it will repeatedly calculate f(n-2) and other small problems, the time complexity is o(2^h-1) = o(2^n). The memory recursive method is used to make the space complexity o(n).

Using a bottom-up approach:

Step 1: state definition: set dp [] one-dimensional array, where dp[i] represents the first number

Step 2 transfer equation: dp[n] = dp[n-1]+dp[n-2] represents the transfer equation of the nth number

Step 3 initial state: dp[0] = 0 dp[1] = 1

Step 4 return value: dp[n], and the last number is the final result

Use the idea of rolling array to optimize (use one constant variable to store the result and two constant variables to store the other two values of the transfer equation)


class Solution:
    def fib(self, n: int) -> int:
        a,b = 0,1
        for _ in range(n):
            a,b = b,a+b
        return a%1000000007

Frog jumping steps of the same type: Sword finger Offer 10- II. Frog jumping steps


class Solution:
    def numWays(self, n: int) -> int:
        a,b = 1,1
        for _ in range(n):
            a,b = b,a+b
        return a%1000000007

Only the initial value is modified. The initial value of the problem is Fibonacci sequence, excluding 0, f(0) = 1, f(1) = 1. The transfer equation is the same as f(n) = f(n-1) +f(n-2), because the frog jumps in one or two steps. If one step is used, f(n-2) and if two steps, f(n-1)

Sword finger Offer 63. Maximum profit of stock

Status definition:

Define dp [] array, dp[i] represents the maximum profit of the current day I

Transfer equation:

dp[i] = max(dp[i-1],prices[i]-min(prices[0:i]))

Initial state:

DP [0] = 0 (profit on the first day is 0)

Return value:

dp[-1] current maximum profit

This problem can optimize time complexity and space complexity. Time complexity Optimization: use constant variables to update the minimum value of prices[0:i], reduce o (i) to o (1), and space complexity Optimization: the previous dp[i-1] (use the result to replace it)


class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if not prices:
            return 0
        mincost = prices[0] 
        res = 0
        for i in prices:
            mincost = min(i,mincost)
            res = max(res,i-mincost)
        return res

Define the minimum value as the first value of the price, and the initial value of the result is 0. Then, obtain the current minimum price first, and then compare the prices.

Sword finger Offer 42. Maximum sum of continuous subarrays

Status definition:

dp[i] represents the maximum sum of subarrays to num [i]. Note that it must include num [i] (calculate num [i])

Transfer equation:

When DP [I-1] < 0, its negative contribution to the array sum is directly equal to nums[i]

When DP [I-1] > = 0, it can be added to the current number without considering the impact on the next number.

Initial state:


Return value:

return max(dp), because it may make a negative contribution to the last number at the end, and the maximum value may be generated in the middle.

Space complexity optimization, directly operate in the original array, space complexity o(1)


class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        for i in range(1,len(nums)):
            nums[i] = nums[i]+max(nums[i-1],0)
        return max(nums)

Sword finger Offer 47. Maximum value of gift

Status definition:

dp [] [] two-dimensional array dp, which records the maximum value of gifts in each grid

Transfer equation:

dp[i][j] = max(grid[i][j]+dp[i-1][j],grid[i][j]+dp[i][j-1])

Initial state:

dp[0][0] = grid[0][0]

In the subsequent definition of dp, you should pay attention to the first and second rows of two dimensions

Return value:


Space complexity optimization, operate in the original grid two-dimensional array, and optimize to o (1)


class Solution:
    def maxValue(self, grid: List[List[int]]) -> int:
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if i==0 and j==0:continue
                if i==0 :
                    grid[i][j] = grid[i][j]+grid[i][j-1]
                elif j ==0:
                    grid[i][j] = grid[i][j]+grid[i-1][j]
                    grid[i][j] = max(grid[i][j]+grid[i-1][j],grid[i][j]+grid[i][j-1])
        return grid[-1][-1]

Sword finger Offer 46. Translate numbers into strings

Status definition:

dp[i] is all possible numbers of the current string I

Transfer equation:

When int(num[i-1:i+1])  <=  twenty-five   and   int(num[i-1])!=0 (the first two strings do not exceed 25 and the first character is not 0) DP [i]  =  dp[i-1]  +  dp[i-2]

In other cases, dp[i] is only equal to dp[i-1] (because the last two numbers can only be used as two characters, not one character,)

Initial state:

dp[0] = 1. dp[1] depends on whether the two digits are greater than 25. If it is greater than 25, it is equal to 1, and if it is less than 2.

Return value:

dp[-1] (directly returning the last value of dp array is the result)


class Solution:
    def translateNum(self, num: int) -> int:
        if num <10:return 1
        num = str(num)
        dp = [None]*len(num)
        dp[0] = 1
        if int(num[:2]) <= 25:
            dp[1] = 2
        else :
            dp[1] = 1
        for i in range(2,len(num)):
            if int(num[i-1:i+1]) <= 25 and int(num[i-1])!=0:
                dp[i] = dp[i-1] + dp[i-2]
                dp[i] = dp[i-1]
        return dp[-1]

Sword finger Offer 48. Longest substring without duplicate characters

Status definition:

dp[i] represents the maximum non repeating string of the current I

Transfer equation:

j is the previous subscript of the current character. When I-j > DP [I-1], dp[i] = dp[i-1]+1

When I-J < = DP [I-1], dp[i] = i - j

Initial state:

dp[0] = 1

Return value:

Max (DP) maximum value of DP array

This problem needs to use the data structure of hash table to store the subscript of array (j in dp idea above)

Space complexity Optimization: using the idea of rolling array, temp records the current dp[i-1], and res is the maximum value in the array, which is always updated,


class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        if not s: return 0
        res = temp = 0
        hashmap = {}
        for j in range(len(s)):
            i = hashmap.get(s[j],-1)
            temp = temp + 1 if temp<j - i else  j - i
            hashmap[s[j]] = j
            res = max(temp,res)
        return res

Others in this document:

Common time complexity:

The order from small to large is o(1) < o (log2n) < o (n) < o (nlog2n) < o (n ^ 2) < o (n ^ 3) < o (2 ^ n) < o (n!) < o (n ^ n)

The representative algorithm of log2n is binary and half search: each incoming surname is halved to 1 / 2, and a total of K operations are performed. Because there is only one final result, there is n*(1/2)^k = 1, derived 2^k = n, and then K is logn

n indicates that the algorithm is a linear algorithm with one cycle

n^2 represents various simple algorithms for sorting arrays

Tags: Algorithm data structure Dynamic Programming

Posted on Sat, 23 Oct 2021 01:44:33 -0400 by shaunmckinnon