LeetCode--Summary of basic concepts of dynamic programming and analysis of classic topics

table of Contents

Divide&Conquer + optimal substructure

Key points of dynamic programming

Topic 1: Fibonacci number

Topic 2: Different paths

Topic 3: The longest common subsequence

Topic 4: The smallest path sum of the triangle

Topic 5: Maximum Subsequence Sum

Topic 6: Change of change


Divide&Conquer + optimal substructure

1. There is no fundamental difference between dynamic programming and recursion or divide and conquer (the key depends on whether there is an optimal substructure)

2. Commonness: find duplicate sub-problems

3. Difference: optimal substructure, sub-optimal solutions can be eliminated in the middle

Key points of dynamic programming

1. Optimal substructure

2. Store intermediate state

3. Recurrence formula (beautiful name: state transition equation or dp equation)

Topic 1: Fibonacci number

(Subject link: https://leetcode-cn.com/problems/fibonacci-number/ )

Fibonacci number, usually expressed by F(n), the sequence formed is called Fibonacci sequence. The number sequence starts with 0 and 1, and each number after it is the sum of the previous two numbers. That is:

F(0) = 0, F(1) = 1
F(n) = F(n-1) + F(n-2), where n> 1
gives you n, please calculate F(n) 

Idea: Use dynamic programming that is dynamic recursion

class Solution {
    public int fib(int n) {
        if(n < 2){return n;}
        int a = 0;
        int b = 1;
        int sum = 0;
        for(int i =2;i<=n;i++){
            sum = a+b;
            a = b;
            b = sum;
        }
        return sum;
    }
}

Topic 2: Different paths

(Subject link: https://leetcode-cn.com/problems/unique-paths/ )

A robot is located in the upper left corner of an mxn grid (the starting point is marked as "Start" in the figure below).

The robot can only move one step down or to the right at a time. The robot tries to reach the bottom right corner of the grid (labeled "Finish" in the image below).

How many different paths are there in total?

Idea: There are two ways to advance from the starting point: 1) Either go one step to the right; 2) Either go one step further

That is to say, how many schemes each grid has is equal to the sum of the scheme of the grid on its right + the scheme of the grid below it .

Obviously, the scheme of each grid in the bottom row is 1, and the scheme of each grid in the rightmost column is also 1.

class Solution {
    public int uniquePaths(int m, int n) {
        int f[][] = new int[m][n];
        for(int j =0;j<n;j++){
            f[m-1][j] = 1;
        }
        for(int i =0;i<m;i++){
            f[i][n-1] = 1;
        }
        for(int i =m-2;i>=0;i--){
            for(int j = n-2;j>=0;j--){
                f[i][j] = f[i+1][j]+f[i][j+1];
            }
        }
        return f[0][0];
    }
}

Topic 3: The longest common subsequence

(Subsequence link: https://leetcode-cn.com/problems/longest-common-subsequence/ )

Given two strings text1 and text2, return the length of the longest common subsequence of these two strings.

A subsequence of a character string refers to a new character string: it is a new character string formed by deleting some characters (or without deleting any characters) from the original character string without changing the relative order of the characters.
For example, "ace" is a subsequence of "abcde", but "aec" is not a subsequence of "abcde". The "common subsequence" of two strings is the subsequence shared by the two strings.

If the two strings have no common subsequence, 0 is returned.

Example 1:

Input: text1 = "abcde", text2 = "ace" 
Output: 3  
Explanation: The longest common subsequence is "ace", and its length is 3

Idea: The longest common subsequence problem. In terms of experience, treat two strings as the rows and columns of a two-dimensional array.

Each point in the two-dimensional array corresponds to two strings. The length of the common string before this point

Create a new array with one more row and one column, one is to initialize to 0, and an empty string that does not need to discuss the row and column with index 0 separately

Recurrence formula:

if(c1 == c2){
    dp[i+1][j+1] = dp[i][j]+1;
}else{
   dp[i+1][j+1] = Math.max(dp[i+1][j],dp[i][j+1]);
}

class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        int m = text1.length();
        int n = text2.length();
        int[][] dp = new int[m+1][n+1];
        for(int i=0;i<m;i++){
            for(int j = 0;j<n;j++){
                char c1 = text1.charAt(i);
                char c2 = text2.charAt(j);
                if(c1 == c2){
                    dp[i+1][j+1] = dp[i][j]+1;
                }else{
                    dp[i+1][j+1] = Math.max(dp[i+1][j],dp[i][j+1]);
                }
            }
        }
        return dp[m][n];
    }
}

Topic 4: The smallest path sum of the triangle

(Subject link: https://leetcode-cn.com/problems/triangle/ )

Given a triangle, find the minimum path sum from top to bottom.

Each step can only move to the adjacent node in the next row. The adjacent node here refers to the subscript and the subscript of the node on the previous layer

Two nodes that are the same or equal to the subscript + 1 of the previous layer. In other words, if it is located at the subscript i of the current line, then the next step can be moved to the subscript i or i + 1 of the next line.

Example 1:

Input: triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
Output: 11
Explanation: As shown in the following diagram:
   2
  3 4
 6 5 7
4 1 8 3
The minimum path sum from top to bottom is 11 (ie, 2 + 3 + 5 + 1 = 11).

Idea: Adopt dynamic programming, bottom-up, and rise layer by layer.

Each layer takes the corresponding minimum path.

The dynamic recurrence equation is: dp[j]= Math.min(dp[j],dp[j+1])+triangle.get(i).get(j)

class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int[] dp = new int[triangle.size()+1];
        for(int i=triangle.size()-1;i>=0;i--){
            for(int j =0;j<triangle.get(i).size();j++){
                dp[j]= Math.min(dp[j],dp[j+1])+triangle.get(i).get(j);
            }
        }
        return dp[0];
    }
}

Topic 5: Maximum Subsequence Sum

(Topic link: https://leetcode-cn.com/problems/maximum-subarray/ )

Given an integer array nums, find the one with the largest sum

Consecutive sub-array (the sub-array contains at least one element), return its maximum sum.

Example 1:

Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: The sum of consecutive sub-arrays [4,-1,2,1] is the largest, which is 6 

Idea: Find the recurrence equation:

Maximum suborder sum = the current element's own value or the value after including the previous element.

The dp equation is: f[i] = max( f [i-1], 0) + a[i]

class Solution {
    public int maxSubArray(int[] nums) {
        int maxsum=nums[0];
        for(int i =1;i<nums.length;i++){
            nums[i] = nums[i]+Math.max(0,nums[i-1]);
            if(nums[i]>maxsum){
                maxsum = nums[i];
            }
        }
        return maxsum;
    }
}

Topic 6: Change of change

(Subject link: https://leetcode-cn.com/problems/coin-change/ )

Given coins of different denominations and a total amount. Write a function to calculate the minimum number of coins required to make up the total amount.

If no coin combination can make up the total amount, return -1. You can think that the number of each coin is unlimited.

Example 1:

Input: coins = [1, 2, 5], amount = 11
Output: 3 
Explanation: 11 = 5 + 5 + 1

Idea: Use dynamic programming.

The dp equation is f(n) = min {f(nk), for k in coin array} +1 

Programming ideas:

First initialize each element of dp table to amount +1 (Integer.MAX_VALUE is also OK), if the final value of dp[amount] is still the initialized value, it means that there is no exchange situation

In the variable dp, if the amount can be made up, the number of times is updated, and if the amount cannot be made up, it is not updated.

class Solution {
    public int coinChange(int[] coins, int amount) {
        int maxvalue = amount+1;
        int[] dp = new int[amount+1];
        Arrays.fill(dp,maxvalue);
        dp[0] = 0;
        for(int i=1;i<amount+1;i++){
            for(int j=0;j<coins.length;j++){
                if(coins[j]<=i){
                    dp[i] = Math.min(dp[i],dp[i-coins[j]]+1);
                }
            }
        }
        return dp[amount] == amount+1 ? -1 : dp[amount];
    }
}

 

Guess you like

Origin blog.csdn.net/yezonghui/article/details/112055518