Force button brush question frame

Posted by etherboo on Mon, 17 Jan 2022 09:28:07 +0100

This paper mainly summarizes the common points of dynamic programming problems in force buckle, obtains a general solution and algorithm framework, and solves more problems according to this scheme and framework. It's also labuladong's algorithm note taking
Original link: https://labuladong.gitee.io/algo/

Question form: find the maximum value, what is the longest increasing subsequence balabalabala. The core problem is exhaustive, because if you want the best value, you have to find all the answers and then find the best value.
Features: there are overlapping subproblems and optimal substructures (from the subproblem to the original problem)
Key: state transition equation.
Basic algorithm framework

# Initialize base case
dp[0][0][...] = base
# State transition
for Status 1 in All values of status 1:
    for Status 2 in All values of status 2:
        for ...
            dp[Status 1][Status 2][...] = Find the most value(Select 1, select 2...)

1.1 problem of collecting change

1. Title Description

Given coins of different denominations, coins and a total amount. Write a function to calculate the minimum number of coins needed 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.

input
coins = [1, 2, 5], amount = 11

output
3

explain
11 = 5 + 5 + 1

2. Solution 1: violent exhaustion (recursion)

This is a dynamic programming problem - seeking the maximum value, with optimal substructure, and the subproblems are independent of each other

For example, if you want to find the minimum number of coins (original question) when amount = 11, if you know how to round up the minimum number of coins (sub question) when amount = 10, you only need to add one to the answer of the sub question (and choose a coin with a face value of 1) to be the answer to the original question. Because the number of coins is unlimited, there is no mutual system between subproblems and they are independent of each other.

Then start to list the equation of state, as follows:

  1. Determine base case: when the target amount is 0, the algorithm returns 0.
  2. Determine the state, that is, the variable that will change in the original problem and subproblem: the number of coins in the problem is infinite and the face value is given, then the only variable is amount. Only the target amount will keep approaching the base case.
  3. Determining the choice, that is, the behavior leading to the state transition: why the state will change is because the coin is selected. For each coin with face value, the target amount will be reduced.
  4. DP function: the solution is top-down, so there will be a recursive DP function. The parameter is the amount that will change in the state transition, that is, the target amount, and the return value is the amount to be calculated, that is, the number of gold coins.

d p ( n ) = { 0 , n = 0 − 1 , n < 0 m i n { d p ( n − c o i n ) + 1 ∣ c o i n ∈ c o i n s } , n > 0 dp(n) = \begin{cases}0,n=0\\-1,n<0\\min\{dp(n-coin)+1|coin \in coins\},n>0\end{cases} dp(n)=⎩⎪⎨⎪⎧​0,n=0−1,n<0min{dp(n−coin)+1∣coin∈coins},n>0​

   //Violent recursion
    //Time complexity is an exponential level (recursive tree can be normalized), and time complexity is the number of nodes in the recursive tree × Time complexity of each recursion)
    //Timeout in the force buckle because the subproblem is calculated repeatedly
    public int coinChange(int[] coins, int amount) {
        if(amount==0) return 0;
        if(amount<0) return -1;
        int res = Integer.MAX_VALUE;
        for(int coin:coins){
            int sub = coinChange(coins,amount-coin);
            if(sub == -1) continue;
            res = Math.min(res,sub+1);

        }
        if(res!=Integer.MAX_VALUE)
            return res;
        else
            return -1;
    }

3. Problem solving idea 2: recursion with memo

Idea 1 because a large number of subproblems are repeatedly calculated, a "Memo" can be used to record the solution of the subproblem. In this way, during the state transition, first look up the memo to see if the solution of the sub problem can be used directly. In this way, the number of subproblems can be reduced to the total amount n. whether the processing time remains unchanged or k, the time complexity is O ( k n ) O(kn) O(kn).

   //Recursion with memo
    public int coinChange2(int[] coins, int amount) {
        if(amount<1) return 0;
        return coinChange2(coins,amount,new int[amount+1]);

    }
    public int coinChange2(int[] coins, int amount,int[] memory) {
        //base case
        if(amount==0) return 0;
        if(amount<0) return -1;
        //View memo to avoid double counting
        if(memory[amount]!=0) return memory[amount];
        int res = Integer.MAX_VALUE;
        for(int coin:coins){
            int sub = coinChange2(coins,amount-coin,memory);
            if(sub == -1) continue;
            res = Math.min(res,sub+1);

        }
        if(res!=Integer.MAX_VALUE) {
            memory[amount] = res;
        }
        else{
            memory[amount] = -1;

        }
        return memory[amount];

    }

4. Problem solving idea 3: dp

Both idea 1 and idea 2 perform state transition from top to bottom. Idea 2 uses memos to store the solutions of all sub problems. We can also use dp table to record the solutions of sub problems and solve the problem of overlapping sub problems. That is, bottom-up
Idea 1 and idea 2 realize state transition by defining recursive functions:
dp function: enter the target amount and return the number of coins with the least target amount
Idea 3: realize state transition by defining recursive array:
dp array: when the target amount is I, at least dp[i] coins are required.
The code is written according to the state transition equation

    //dp array iteration
    public int coinChange3(int[] coins, int amount) {
        //base case
        if(amount==0) return 0;
        if(amount<0) return -1;
        int[] dp = new int[amount+1];
        int max = amount+1;//The number of coins used will not exceed amount+1, and the worst is to use amount of 1 yuan coins
        Arrays.fill(dp,max);//First set all parts to maximum
        dp[0] = 0;
        for(int i=1;i<=amount;i++){
            for(int coin:coins){
                if(i - coin<0) continue;
                dp[i] = Math.min(dp[i],1+dp[i-coin]);

            }
        }
        return dp[amount] > amount ? -1:dp[amount];

    }

Topics: Algorithm leetcode