1 Introduction
递归
and 动态规划
are the two leaders in the algorithm world. If you want to enter the door of algorithms, you must understand and master the essence of these two algorithms. Once you understand the essence of 2
this algorithm, coupled with an in-depth understanding of complex data structures such as trees and graphs, you can solve most of the algorithm problems.
This article uses several typical cases to talk about the dynamic programming algorithm again. In fact, the dynamic programming algorithm is also 2
a brush.
- Find all alternatives for the current subproblem, choosing the largest or smallest value among all alternatives.
- The optimal solution to this subproblem is an option for the next subproblem. Finally deduce the final result. Each sub-problem only needs to care about the results of its dependent sub-problems without paying attention to its implementation process.
The basic concept of dynamic programming: step by step, choose the best every time, and finally achieve the best.
Here are a few cases to understand how dynamic programming works step by step.
2. MostA
2.1 Problem Description
Now suppose there is a special keyboard containing the following keys:
-
Key 1: (A)
: Print one on the screenA
. -
Key 2
:(ctrl-A)
: Select the entire screen. -
Key 3: (ctrl-c):
copy selected area to buffer -
Key 4: (ctrl-v) :
Output the contents of the buffer to the end of the last input and display it on the screen.
Now, you can only press the key N
times (using the above four keys), how many can be displayed on the screen at most A
?
2.2 Sample
2.2.1 Sample1
Input: N =
3
Output: 3
Explanation: We can display up to three on the screen A
by pressing the keys in the following order:
A,A,A
2.2.2 Sample2
Input: N = 7
Output: 9
Explanation: We can display at most on the screen 9
, A
press the keys in the following order
A,A,A,ctrl-A,ctrl-c,ctrl-V, ctrl V
2.3 Problem analysis
This question is a question of seeking the maximum value, which can be realized using dynamic programming. As mentioned earlier, to use the dynamic programming algorithm, we must first know which options are available for each sub-problem.
Tips: As far as this question is concerned, the number of different keystrokes can be considered as a sub-problem.
To output on the screen , that is, to change the number of characters A
on the screen , there are options:A
2
- Press the key directly
A
. Only one keystroke is needed to output 'A'. - Copy on screen
A
. Press firstctrl+A、ctrl+C
to add content to the buffer, and then press repeatedly toctrl+v
output letters on the screenA
.
Which one is the best choice under different number of keystrokes?
What the dynamic programming algorithm does in this question is:
- From the accumulation in the small-scale state to the result in the large-scale state. What this question needs to calculate is the number of children and mothers when the number of keys changes
A
. - When the number of state quantities changes, it is necessary to choose the most ideal solution.
Problem-solving process:
You can first define a one-dimensional dp
array. It is used to store the number of sub-parents in different states A
.
Now analyze which option can get the most ideal result under different times.
- When the number of key presses
1
is . In this state, it is only possibleA
to output parent and child by pressing the keyA
.
- When the number of key presses
2
is . It is also only possible to output the letter A by directly pressing the A key. At this time, the number of letters on the screen isdp[2]=dp[1]+1
.
-
When the number of key presses
3
is . By directly pressing the 'A' key, A can also be output by copying.The number of directly pressed
A
keys isdp[3]=dp[2]+1
.
复制输出`A`。因复制的前置条件是要先按下`ctrl+A、ctrl+C`,意味着需要消耗掉2次按键,`ctrl+V`复制的内容应该是`dp[0]`位置字母`A`的个数。
Obviously, there are more letters output by direct keys A
. It is the best scheme to choose to directly press the sub-keys in the two schemes.
-
When the number of key presses
4
is .A
Press the key directly to input, and the charactersA
on the screen are .A
4
When outputting on screen using a copy scheme A
. There are two ways to copy 2
:
At dp
array 1
position ctrl+A
, 2
at ctrl+C
. What is copied in this way is dp[0]
the number of sub-parents of the position.
at dp
array position 2
, ctrl+A
at 3
position ctrl+C
. What is copied in this way is dp[1]
the number of sub-parents of the position.
Encoding implementation:
#include <iostream>
using namespace std;
//一维动态数组
int dp[100]= {0};
//按键次数
int n;
int main(int argc, char** argv) {
cin>>n;
for(int i=1; i<=n; i++) {
//直接按下A键
dp[i]=dp[i-1]+1;
//如果复制
for( int j=2; j<i; j++ ) {
dp[i]=max( dp[i],dp[j-2]*(i-j+1) );
}
}
cout<<dp[n];
return 0;
}
3. Longest increasing subsequence
3.1 Problem description
Given an unordered array of integers, find the length of the longest ascending subsequence in it.
Example:
-
enter:
[10,9,2,5,3,7,101,18]
-
output:
4
Explanation: The longest ascending subsequence is [2,3,7,101]
, and its length is 4
.
Explanation: There may be multiple combinations of the longest ascending subsequence, you only need to output the corresponding length. The difference between a subsequence and a substring is that the substring is continuous, but the subsequence is not necessarily continuous.
### 3.2 Problem Analysis
How to solve this problem using dynamic programming idea.
- Create a one-dimensional dynamic
dp
array. Record the length of the subsequence when the size of the data in the array changes. The initial value1
is that the sequence is its own subsequence.
- Scan the original array from left to right, and when the data is scanned
10
, obviously, the number of its subsequences is1
.
- When the data is scanned
9
, it10
is compared with the previous one. Because it is smaller than it,9
it cannot contribute to the incremental subsequence, and the number of the original subsequence is retained.
- When scanned
2
,dp
the value in the corresponding array is1
.
- When scanned
5
, its ratio is10、9
small, but the ratio2
is large, which can2
become an increasing subsequence of the current state value.
- When the scan arrives ,
3
the longest subsequence should be added to the longest subsequence at the end because the ratio is large .3
2
2
1
- When the scan arrives
7
, because7
the ratios2,5,3
are all large, it is necessary2、5、3
to find the maximum value in the longest subsequence at the end. The characteristic of dynamic programming is that when the state changes, it is often necessary to choose the best among multiple options.
- In the same way, when it is scanned
101
, because it is larger than all the previous numbers, you need todp
find the maximum value in the already filled array and add it1
.
- By the same principle,
dp
the values in the final array should look like this.
3.3 Encoding implementation
#include <iostream>
#include <cstring>
using namespace std;
//原始数组
int nums[]= {10,9,2,5,3,7,101,18};
//一维动态数组
int dp[100]= {1};
int main(int argc, char** argv) {
int size=sizeof(nums)/sizeof(int);
//最长子序列
int maxVal=1;
//遍历原始数组
for( int i=0; i<size; i++ ) {
dp[i]=1;
//以 i 为当前位置,向原始数组之间扫描
for( int j=i-1; j>=0; j-- ) {
if( nums[i]>nums[j] ) {
dp[i]=max(dp[i] ,dp[j]+1 ) ;
}
}
if(maxVal<dp[i]) maxVal=dp[i];
}
for(int i=0; i<size; i++)
cout<<dp[i]<<"\t";
cout<<"\n最长子序列长度:"<< maxVal<<endl;
return 0;
}
4. Minimum path sum
4.1 Problem description
There is a two-dimensional array nums
in which the elements are all non-negative integers . Now you are standing in the upper left corner, you can only move to the right or down , and you need to reach the lower right corner. Now please calculate, what is the minimum sum of the path you have passed?
A two-dimensional array is shown in the figure below.
This question is a typical 动态规划类
question type.
The basic process is as follows:
- Based on the basic idea of dynamic programming, first create a two-dimensional
dp
array. Store the sum of the shortest paths from the starting location to each location in the table. The basic routine of dynamic programming is step by step. If the path sum from the starting point to each location can be guaranteed to be the smallest, the shortest path sum to the destination can naturally be obtained.
dp
Populate the table with some obvious values first, also known asbase case
. For example, the shortest path of the starting point is itself, as shown in the following figure:
dp
The value of the first row in the table is only affected by the value on the left, there are no multiple choices, and it is easy to find out. Its value isdp[0][i]=dp[0][i-1]+nums[0][i]
.
dp
The value of the first column in the table is only affected by the upper edge value, and there is no multiple selection, its value isdp[i][0]=dp[i-1][0]+nums[i][0]
.
- For values at other positions, you need to select the minimum value from the values on the top and left and then add it to the value at the same position in the original array. As shown in the figure below ,
A
there are2
three choices, choose the smaller value.
- By analogy, the values of all remaining positions can be obtained. As shown in the image below, the red numbers indicate the final selection.
- Finally, the sum of the shortest paths from the starting point to the destination is drawn.
4.2 Encoding implementation
#include <iostream>
#include <cstring>
using namespace std;
//原始数组
int nums[3][3]= { {2,4,3},
{7,6,2},
{1,8,5},
};
//二维动态数组
int dp[3][3]= { {0,0,0},
{0,0,0},
{0,0,0},
};
int main(int argcwfh, char** argv) {
//起始位置的路径路径是本身
dp[0][0]=nums[0][0];
//第一行值只受左边值影响
for(int i=1; i<3; i++ ) {
dp[0][i]=dp[0][i-1]+nums[0][i];
}
//第一列值只受上边影响
for(int i=1; i<3; i++ ) {
dp[i][0]=dp[i-1][0]+nums[i-1][0];
}
//由上向下
for(int i=1; i<3; i++) {
for(int j=1; j<3; j++ ) {
dp[i][j]=nums[i-1][j-1]+min(dp[i][j-1],dp[i-1][j]);
}
}
for(int i=0; i<3; i++) {
for(int j=0; j<3; j++ ) {
cout<<dp[i][j]<<"\t";
}
cout<<endl;
}
return 0;
}
5. Summary
Recursion and dynamic programming are the two major swordsmen in the algorithm world. They communicate with each other. When solving the same problem, one stands in the positive direction of the problem domain and the other stands in the opposite direction of the problem domain. The flexible use and mastery of these two algorithms is a compulsory path to the algorithm world.