Dynamic programming problem

Posted by chieffan on Thu, 06 Jan 2022 00:09:22 +0100

Fibonacci

Title Description:

We all know the Fibonacci sequence. Now it is required to input a positive integer n. please output the nth item of the Fibonacci sequence.

Problem solving ideas:
1. Recursion
2. Dynamic planning
Status: F(n)
State recurrence: F(n)=F(n-1)+F(n-2)
Initial value: F(1)=F(2)=1
Return result: F(N)

Code implementation:
Method 1: recursion (low efficiency):

class Solution{public: int Fibonacci(int n)
{        // Initial value 
	if (n <= 0)
	{ 
		return 0; 
	} 
	if (n == 1 || n == 2) 
	{
		return 1; 
	}        
	// F(n)=F(n-1)+F(n-2) 
	return Fibonacci(n - 2) + Fibonacci(n - 1); }};

Method 2: dynamic programming

class Solution {
public:
    int Fibonacci(int n) {
        if(n==1 || n==2)
            return 1;
        int fn;
        int fn1 = 1, fn2 = 1;
        for(int i = 2; i < n; i++)
        {
            fn = fn1 + fn2;
            fn1 = fn2;
            fn2 = fn;
        }
        
        return fn;
        /*The space complexity of the above solution is O(n)
        In fact, F(n) is only related to the first two items adjacent to it,
        Therefore, it is not necessary to save the solutions of all subproblems
        You only need to save the solutions of the two subproblems
        The spatial complexity of the following method will be O(1)*/
        if(n==1 || n==2)
            return 1;
        int* F = new int[n];
        //Initial state
        F[0] = 1;
        F[1] = 1;
        for(int i = 2; i < n; i++)
        {
            F[i] = F[i-1] + F[i-2];
        }
        
        return F[n-1];
    }
};

String break

Title Description:

Given a string s and a group of words dict, judge whether s can be divided into a word sequence with spaces, so that all words in the word sequence are words in dict (the sequence can contain one or more words).
For example:
Given s = "nowcode";
dict=["now", "code"].
Returns true because "nowcode" can be split into "now code"

Problem solving ideas:
Status:

  • Substatus: can the first 1, 2, 3,..., n characters be successfully segmented according to the words in the dictionary
  • F(i): whether the first i characters can be successfully segmented according to the words in the dictionary

Status recurrence:

  • F(i): true {J < i & & F(j) & & substr [j+1, i] can find} OR false in the dictionary. In J less than i, F(i) is true as long as F(j) can be found and characters from j+1 to i can be found in the dictionary

Initial value:

  • If the initial value cannot be determined, an empty state that does not represent the actual meaning can be introduced. As the value of the initial empty state of the state, it is necessary to ensure that the state recurrence can be carried out correctly and smoothly. What value can be taken can be verified by a simple example. F(0) = true

Return result: F(n)

Code implementation:

class Solution {
public:
    bool wordBreak(string s, unordered_set<string> &dict) {
        int len = s.size();
        vector<bool> F(len+1, false);
        F[0] = true;
        for(int i = 1; i <= len; i++)
        {
            //Status of F[8]: 7 < 8 & & F [7] & & [8,8]
            //Status of F[8]: 6 < 8 & & F [6] & & [7,8] 
            for(int j = i-1; j >= 0; j--)
            {
                if(F[j] && dict.find(s.substr(j,i-j)) != dict.end())
                {
                    F[i] = true;
                    break;
                }
            }
        }
        
        return F[len];
    }
};

Triangular matrix

Title Description:

Give a triangle and calculate the minimum path sum from the top to the bottom of the triangle. Each step can move to the next row of adjacent numbers,
For example, the triangle given is as follows:
[[20],[30,40],[60,50,70],[40,10,80,30]]

Problem solving ideas:
State: sub state: shortest path from (0,0) to (1,0), (1,1), (2,0),... (n,n) and F(i,j): shortest path from (0,0) to (i,j)
State recurrence: F (I, J) = min (f (i-1, J-1), f (i-1, J)) + triangle [i] [J]
Initial value: F(0,0) = triangle[0][0] return result: min(F(n-1, i))

Code implementation:

class Solution {
public:
    int minimumTotal(vector<vector<int> > &triangle) {
        if(triangle.empty())
            return 0;
        int row = triangle.size();
        vector<vector<int> > minSum(triangle);
        for(int i = 1; i < row; i++)
        {
            for(int j = 0; j <= i; j++)
            {
                if(j == 0)
                    minSum[i][j] = minSum[i-1][j] + triangle[i][j];
                else if(j == i)
                    minSum[i][j] = minSum[i-1][j-1] + triangle[i][j];
                else
                    minSum[i][j] = min(minSum[i-1][j], minSum[i-1][j-1])
                                   + triangle[i][j];
            }
        }
        int result = minSum[row-1][0];
        for(int i = 1; i < triangle.size(); i++)
        {
            result = min(result, minSum[row-1][i]);
        }
        
        return result;
    }
};

Total number of paths (Unique Paths)

Title Description:

A robot in m × The upper left corner (starting point) of the n-size map.
The robot can move down or right at a time. The robot will reach the lower right corner of the map (end point).
How many different paths can you take from the beginning to the end?

Problem solving ideas:
Status: substatus: number of paths from (0,0) to (1,0), (1,1), (2,1),... (m-1,n-1): number of paths from (0,0) to F(i,j)
State recurrence: F(i,j) = F(i-1,j) + F(i,j-1)
Initialization: special case: row 0 and column 0 F(0,i) = 1 F(i,0) = 1
Return result: F(m-1,n-1)

Code implementation:

class Solution {
public:
    /**
     * 
     * @param m int integer 
     * @param n int integer 
     * @return int integer
     */
    int uniquePaths(int m, int n) {
        // write code here
        vector<vector<int> > ret(m, vector<int>(n,1));
        for(int i = 1; i < m; i++)
        {
            for(int j = 1; j < n; j++)
            {
                ret[i][j] = ret[i-1][j] + ret[i][j-1];
            }
        }
        
        return ret[m-1][n-1];
    }
};

Minimum path sum

Title Description:

Given a two-dimensional array of m x n filled with non negative integers, now to go from the upper left corner to the lower right corner of the two-dimensional array, please find the path with the smallest sum of all numbers on the path.
Note: you can only move down or right at a time.

Problem solving ideas:
State: sub state: shortest path F(i,j) from (0,0) to (1,0), (1,1), (2,1),... (m-1,n-1): shortest path from (0,0) to F(i,j).
State recurrence: F (I, J) = min {f (i-1, J), f (I, J-1)} + (I, J)
Initialization: F(0,0) = (0,0) special case: row 0 and column 0 F(0,i) = F(0,i-1) + (0,i) F(i,0) = F(i-1,0) + (i,0)
Return result: F(m-1,n-1)

Code implementation:

class Solution {
public:
    /**
     * 
     * @param grid int Integer vector < > > 
     * @return int integer
     */
    int minPathSum(vector<vector<int> >& grid) {
        // write code here
        if(grid.size() == 0 || grid[0].size() == 0)
            return 0;
        int M = grid.size();
        int N = grid[0].size();
        vector<vector<int> > ret(M, vector<int>(N,0));
        ret[0][0] = grid[0][0];
        for(int i = 1; i < N; i++)
        {
            ret[0][i] = ret[0][i-1] + grid[0][i];
        }
        for(int i = 1; i < M; i++)
        {
            ret[i][0] = ret[i-1][0] + grid[i][0];
        }
        for(int i = 1; i < M; i++)
        {
            for(int j = 1; j < N; j++)
            {
                ret[i][j] = min(ret[i-1][j],ret[i][j-1]) + grid[i][j];
            }
        }
        
        return ret[M-1][N-1];
    }
};

Topics: C++ Algorithm data structure Dynamic Programming