[Likou Brush Questions] (3) Dynamic Programming Topics

dynamic programming

1. What problems is dynamic programming suitable for?

Seek the most value, and the core is exhaustive thinking.

First of all, exhaustiveness can be very complicated; so you need to discover 重叠的子问题and then optimize in the form of a dp array using memo mode. That is, you need to find 最优子结构and solve complex problems through sub-problems. To be exhaustive correctly, you also need to find out our状态转移方程。

Optimization of dynamic regression: You can only use dp to store the transition equation. (state compression)

Top-down: start from a big problem and decompose downwards, such as recursion tree;

Bottom-up: Start with a basic problem and work your way up, such as dynamic programming.

The Five Parts of the Motion Rule:

  • Clear the subscript of the dp array and the meaning of the corresponding value
  • Find the subproblem to get the recursive formula
  • Clarify how the dp array is initialized
  • Determine the traversal order
  • Example to derive dp array
for 状态1 in 状态1的所有取值:
    for 状态2 in 状态2的所有取值:
        for ...
            dp[状态1][状态2][...] = 择优(选择1,选择2...)

2, force button question type

2.1,746 minimum cost to climb stairs

输入:cost = [10, 15, 20]
输出:15
解释:最低花费是从 cost[1] 开始,然后走两步即可到阶梯顶,一共花费 15 。
输入:cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
输出:6
解释:最低花费方式是从 cost[0] 开始,逐个经过那些 1 ,跳过 cost[3] ,一共花费 6 。

Link: https://leetcode-cn.com/problems/min-cost-climbing-stairs

class Solution {
    
    
    public int minCostClimbingStairs(int[] cost) {
    
    
        int next = 0;
        int size = cost.length;
        // 当有0层阶梯和1层阶梯时直接跨过去
        int prev = 0;
        int curr = 0;
        
        for(int i =2;i<=size;i++){
    
    
            // 下一步如何走于前两步有关
            // 下一步可以从前两步走两步或者是前一步走一步到达
            next = Math.min(curr+cost[i-1],prev+cost[i-2]);
            prev = curr;
            curr = next;
        }
        return next;
            
    }
}

2.2, 62 different paths

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

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

Q How many different paths are there in total?

img
Link: https://leetcode-cn.com/problems/unique-paths

problem analysis:

dp[i][j]The path of is equal to the dp[i-1][j]sum dp[i][j-1]of the path methods of sum. This is our recursion formula.

Then how to initialize the array: when m or n is 1, there is only one way to go right or left.

Why initialize the array first? Because our result is the final dp array element value, and the entire value is derived from the initial value by a recursive formula. where dp[i][j]represents the path from [0][0]to .[i][j]

image-20210901160624982

class Solution {
    
    
    public int uniquePaths(int m, int n) {
    
    
        int[][] dp = new int[m][n];
        // 如何初始化数组
        for(int i = 0;i<m;i++) dp[i][0] = 1;
        for(int j = 0;j<n;j++) dp[0][j] = 1;
        for(int i=1;i<m;i++){
    
    
            for(int j=1;j<n;j++){
    
    
                // 递推公式
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
}

Also, there are variants of different paths, different paths with obstacles. The idea here is to jump over obstacles, which default to 0.

2.3, 343 integer split

Given a positive integer n , split it into the sum of at least two positive integers and maximize the product of these integers. Returns the largest product you can get.

输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。

Link: https://leetcode-cn.com/problems/integer-break/

Idea: How to split a number n into 2? And calculate the product with the largest? Traverse from 1 to n-1 from j; calculate Max(j*(ij))

How to split a number into n and take the largest? Continue to split the ij just now. j*(dp[ij]). Here our dp[i] represents the maximum product of split i. Further, we get the dp formula:dp[i]=max(dp[i],max(j*(i-j),dp[i-j]*j))

class Solution {
    
    
    public int integerBreak(int n) {
    
    
        // 初始化为0,其他不考虑
        int[] dp = new int[n+1];
        for(int i =1;i<=n;i++){
    
    
            for(int j=1;j<=i/2;j++){
    
    
                dp[i] = Math.max(dp[i],Math.max(j*(i-j),j*dp[i-j]));
            }
        }
        return dp[n];
    }
}

2.4, 300 longest increasing subsequence

Given an array of integers nums, find the length of the longest strictly increasing subsequence in it.

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。

Link: https://leetcode-cn.com/problems/longest-increasing-subsequence/

Consider dynamic programming: the relationship between one element and the maximum length of a sequence of two elements is to add one, as long as the increase is satisfied.

class Solution {
    
    
    public int lengthOfLIS(int[] nums) {
    
    
        int[] dp = new int[nums.length];
        //初始化全部为1;dp[i]表示有i个元素的长度
        Arrays.fill(dp,1);

        int size = nums.length;
        for(int i=1;i<size;i++){
    
    
            for(int j=0;j<i;j++){
    
    
                if(nums[j]<nums[i]){
    
     //满足升序条件
                    dp[i] = Math.max(dp[i],dp[j]+1);
                }
            }
        }
        //取dp数组中最大的为结果
        // 1,3,6,7,9 =>5
	//1,3,6,7,9,4 =>3(会把4取到)
        int result = 1;
        for(int i=0;i<size;i++){
    
    
            result = Math.max(result,dp[i]);
        }
        return result;
    }
}

2.5, 718 Most Frequently Repeated Subarrays

Given two integer arrays Aand B, return the length of the longest subarray common to the two arrays.

输入:
A: [1,2,3,2,1]
B: [3,2,1,4,7]
输出:3

Link: https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/

Define dp[i][j]the longest common subarray representing A[i:] and B[j:]; then the two arrays satisfydp[i][j]=dp[i-1][j-1]+1

class Solution {
    
    
    public int findLength(int[] nums1, int[] nums2) {
    
    
        int s1 = nums1.length,s2 = nums2.length;
        int res = 0;
        //dp[i][j]表示下标为i-1和j-1的数组AB的最长公共子数组
        //因此鉴于ij的定义,他们要从1开始
        int[][] dp = new int[s1+1][s2+1];
      
        for(int i=1;i<s1;i++){
    
    
            for(int j=1;j<s2;j++){
    
    
                dp[i][j] = nums1[i-1]==nums2[j-1]?dp[i-1][j-1]+1:0;
                res = Math.max(dp[i][j],res);
            }
        }
        return res;
    }
}

2.6, 1143 longest common subsequence

Given two strings text1 and text2, return the length of the longest common subsequence of the two strings. Returns 0 if no common subsequence exists.

A subsequence of a string refers to a new string consisting of some characters (or no characters) removed from the original 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 that both strings have in common.

输入:text1 = "abcde", text2 = "ace" 
输出:3  
解释:最长公共子序列是 "ace" ,它的长度为 3 。

Link: https://leetcode-cn.com/problems/longest-common-subsequence

Note: The difference between an array and a sequence is that the array must be contiguous; the sequence can be discontinuous.

image.png
class Solution {
    
    
    public int longestCommonSubsequence(String text1, String text2) {
    
    
        int s1 = text1.length();
        int s2 = text2.length();
        int dp[][] = new int[s1+1][s2+1];
        for(int i=1;i<=s1;i++){
    
    
            for(int j=1;j<=s2;j++){
    
    
                //两层for循环都是轮训填充的
                if(text1.charAt(i-1)==text2.charAt(j-1)){
    
    
                    dp[i][j]=dp[i-1][j-1]+1;
                }else{
    
    
                    //当前不能选的时候,只能是之前选的最大值
                    dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
                }
            }
        }
        return dp[s1][s2];
    }
}

Similar questions:

[583. Deletion of two strings]

2.7, 72 edit distance

https://leetcode-cn.com/problems/edit-distance/

class Solution {
    
    
    public int minDistance(String word1, String word2) {
    
    
        // 思路:dp
        int m = word1.length();
        int n = word2.length();
        int[][] dp = new int[m+1][n+1];
        // 二维数组初始化
        // s1为null,s2需要编辑个数为自己长度
        for(int i=1;i<=m;i++){
    
    
            dp[i][0] = i;
        }
         // s2为null,s1需要编辑个数为自己长度
        for(int j=1;j<=n;j++){
    
    
            dp[0][j] = j;
        }

        for(int i=1;i<=m;i++){
    
    
            for(int j=1;j<=n;j++){
    
    
                if(word1.charAt(i-1)==word2.charAt(j-1)){
    
    
                    // 不用编辑
                    dp[i][j] = dp[i-1][j-1];
                }else{
    
    
                    // 分别执行插入,删除,替换
                    dp[i][j] = min(dp[i][j-1]+1,dp[i-1][j]+1,dp[i-1][j-1]+1);
                }
            }
        }
        return dp[m][n];
    }
    public int min(int a,int b,int c){
    
    
        return Math.min(a,Math.min(b,c));
    }
}

Guess you like

Origin blog.csdn.net/qq_40589204/article/details/120988558