Document directory
- 1.1.1 step jumping Problem
- 1.1.2 maximum and subsequence
- 1.1.3 Joseph Ring
- 1.2.1 longest ascending/descending subsequence (LIS, LDS)
- 1.2.3 edited distance)
- 1.2.4 backpack Problems
- 1.3.2 Short Circuit
Reprinted please indicate the source:
Http://blog.csdn.net/xiaohongsimon/article/details/10264735
Dynamic Programming)
An English explanation of dynamic planning is in place: whenever the results of subproblems are needed, they have alreadybeen computed, and can be simply be looked up in a table. That is, the computation of all subproblems can be completed by the query table. The advantage of dynamic planning is to avoid repeated computation of subproblems as much as possible.
1.1 O (n) Problems
The complexity of the O (n) DP can generally be abstracted as F (n) problem, remember the High School Series question, "known F (n) = 2f (N-1 ), F (0) = 1, find the leading expression of F (N), isn't it easy? However, actual problems often require us to discover this recursive relationship by ourselves, so as to simplify complicated problems.
1.1.1 step jumping Problem
A step has a total of N levels. If you can skip 1 level at a time, you can also skip 2 levels. Calculate the total number of hops in total and analyze the time complexity of the algorithm.
Think of the jump Method for n-level steps as a n function and mark it as F (n ). When N> 2, there are two different options for the first hop: one is the first hop with only one level. At this time, the number of hops equals to the number of hops for the next n-1 level step, that is F (n-1); another option is the first jump level 2, at this time the number of Jump method is equal to the number of the next step of the N-2 level, that is, F (n-2 ). Therefore, F (n) = f (n-1) + (F-2) of different hops at N-level steps ).
1.1.1.1 Recursive Method
From this analysis, I believe many people can see that this is the familiar sequence of fiber ACCI. Directly recursive solving involves a lot of repeated computations. We use solving F (10) as an example to analyze the recursive solving process. F (10) and F (9) and F (8) are required ). Similarly, if F (9) is required, F (8) and F (7)… must be obtained first )......
Before analyzing its complexity, we can intuitively look at the test time curve:
#encoding=utf8 def Fibonacci(n): if n == 1 or n ==0: return 1return Fibonacci(n-1)+Fibonacci(n-2)
Implementation/length |
10 |
20 |
30 |
40 |
Recursion |
4.69e-05 |
0.0046 |
0.5660 |
69.8280 |
I was surprised to see this result, but the length was not over a hundred times. It took me some time to reach an intolerable level. To better understand the complexity, let's draw a picture:
At first glance, I thought it was a linear relationship, right? The ordinate is log10. That is to say, recursion solves this problem. The time complexity is exponential. So how is this exponential level derived?
Only from the recursive formula, N each plus 1, the calculation time is approximately increased to two times (if F (n) = 2f (N-1), then it is easy to see O (N) = 2 ^ N). In fact, the complexity is O (1.618 ^ N). For details, refer to some feature value calculation methods.
1.1.1.2 Dynamic Planning
def Fibonacci_dp(n): res = [1]*(n+1) if n == 1 or n ==0: return 1 for i in range(2,n+1): res[i]= res[i-1]+ res[i-2]return res[n]
Implementation/length |
10 |
20 |
30 |
40 |
Recursion |
4.69e-05 |
0.0046 |
0.5660 |
69.8280 |
DP |
1.09e-05 |
9.05e-06 |
9.06e-06 |
1.09e-05 |
Obviously, the time complexity of DP is O (n), and it only requires a fixed physical space overhead. The reason why this problem is classified as one-dimensional DP, it also requires a one-dimensional secondary array res [n + 1].
In comparison, the performance improvement is very obvious.
1.1.1.3 Matrix Solution
This problem still involves the solution of logn, but it has nothing to do with our DP topic. Please try again later.
1.1.2 maximum and subsequence
Enter an integer array lst []. The array also has a positive number and a negative number. One or more consecutive integers in the array form a sub-array. Each sub-array has a sum. Calculate the maximum value of the sum of all sub-arrays and the sub-array. The time complexity is O (n ).
1.1.2.1 problem Abstraction:
F (n) indicates the sequence 0, 1 ,... The largest sum of N, that is, F (n) represents the largest sum of the array ending with lst [N.
1.1.2.2 recurrence relationship:
F (n) = max (0, F (n-1) + lst (n )).
Example:
LST []: [-5, 7,-2,-6, 5,-1, 4]
F []: [0, 7, 5, 0, 5, 4, 8]
The maximum value of F is 8, which is our final requirement. Start tracing from this position and always encounter a zero position. This interval is the largest and subsequence. Time complexity O (N) and space complexity O (n ).
def max_subsum(lst): n = len(lst) f = [0]*n f[0]= max(lst[0],0) for i in range(1,n): f[i]= max(0,f[i-1]+lst[i]) idx_max = f.index(max(f)) idx_min = idx_max while idx_min>=0and f[idx_min]> 0: idx_min -=1return lst[idx_min+1:idx_max+1]
1.1.2.3 maximum submatrix
This is actually a kind of deformation of the "maximum sub-array" problem, but the one-dimensional problem is converted into a two-dimensional problem. Of course, the solution is to convert the two-dimensional problem into one-dimensional.
First, traverse the child matrix A [I] [N], I = 1, 2 ,... N, all columns are added to obtain a one-dimensional array, and then converted to the maximum sub-array. complexity O (N ^ 3 ).
There is a solution called the "hanging line method" on the Internet (talking about how to solve the largest subrectangle problem with a very big idea, Wang zhikun). This problem can be solved within n ^ 2, I have the opportunity to add more information.
1.1.3 Joseph Ring
Problem description: N count, 0 ~ N-1, 0 is used as the 1st number, and the M number is deleted. The next number of the deleted number is used as the first number in the next round. Delete the number until the next number is left, evaluate the subscript of this number in the original sequence.
Analysis:
F (n, m) indicates n people, according to the rule, the subscript of the remaining person. The first subscript of the number to be deleted is s-1. Then M becomes the beginning of the next round (f (n-1, M), and m + 1 becomes 1...
Subscript of F (n, m) |
After adjustment |
Subscript for F (n-1, m) |
0 |
M |
0 |
1 |
M + 1 |
1 |
... |
M + 2 |
2 |
M-1 (to be deleted) |
... |
... |
M |
N-2 |
N-m-2 |
M + 1 |
N-1 |
N-m-1 |
... |
0 |
N-m |
N-2 |
1... |
N-(m-1 )... |
N-1 |
M-2 |
N-2 |
It is not difficult to find that if the subscript of the last number in F (n-1, m) is X, then it is in F (n, m) the subscript in is (x + M) % N, and the subscript of the last number must be 0, so we can use DP to evaluate
In comparison, this question is more entertaining and not widely used.
1.2 O (N ^ 2) problem 1.2.1 longest ascending/descending subsequence (LIS, LDS)
Given a sequence of A1, A2,... an, without changing the relative order, find its largest subset to meet the requirement that any I <J has AI <AJ
Problem Abstraction:
F [k] indicates the maximum Lis length ending with an AK
Recurrence relationship:
F [k] = max (F [I]) + 1, I <K & AI <AK
def lis_n2(seq): n = len(seq) if n <=0 : return 0 e = [1]* n #e[i] is thelength of sub lis which end with seq[i] step = [-1]* n #step[i] is predecessor of the sub seq.ending at seq[i] for i in range(1,n): _max = 0 for j in range(i): if seq[i]> seq[j]and e[j]>_max: _max = e[j] step[i]= j e[i]= _max+1 # e[i] = max( e[j]) + 1, j= 0...i-1 and seq[i]>seq[j] # max(e) is thelength of lis # further we getthe lis more than its length res = [] idx = e.index(max(e)) while(idx!= -1): res += [seq[idx]] idx = step[idx] res = res[::-1] # reverse return res
1.2.2 Longest Common subsequence (longest common subsequence) 1.2.2.1 Problem Description
Specify two sequences (arrays or strings in C and List in Python) and find the largest common subsequences of the two. The relative sequence of elements in the subsequence remains unchanged and is not necessarily continuous. For example, in "abcdef", "ABC" and "Ace" are counted as subsequences. Of course, it is not difficult to draw a conclusion, a sequence with a length of N with a sub-sequence composition of 2 ^ N (back to arrange the combination)
1.2.2.2 Recursion
The exponential complexity problem often cannot be solved in one step (it is unacceptable to make a direct effort). Therefore, we should consider whether we can solve its subproblems through a roundabout approach. For the two sequences X, Y, whose lengths are n, m, we can find that the LCS results of X and Y can be obtained from one of the three sub-problems:
1. LCS (x1. .. n-1, y1. .. m)
2. LCS (x1. .. n, y1. m-1)
3. LCS (x1. .. n-1, y1. m-1) + public tail Element
def lcs_len(x, y): """This function returns length of longest commonsequence of x and y.""" if len(x)== 0 or len(y)== 0: return 0 if x[-2]== y[-2]: # if last but one elements of x and y areequal return lcs_len(x[:-1], y[:-1])+ 1 else: return max(lcs_len(x[:-1], y), lcs_len(x, y[:-1]))
1.2.2.3 dynamic planning O (N ^ 2)
Apparently, recursive operations introduce many repeated computations. Dynamic Planning can solve this problem. One of its English explanations is very good: whenever the results of subproblems are needed, they have alreadybeen computed, and can simply be looked up in a table. That is, the calculation of all sub-problems can be completed by the table! Let's take a look at the Code:
def lcs_dp(x, y): n = len(x) m = len(y) table = dict() # a hashtable, but we'll use it as a 2Darray here for i in range(n+1): # i=0,1,...,n for j in range(m+1): # j=0,1,...,m if i== 0or j ==0: table[i, j]= 0 elif x[i-1]== y[j-1]: table[i, j]= table[i-1, j-1]+ 1 else: table[i, j]= max(table[i-1, j], table[i, j-1]) # Now, table[n, m]is the length of LCS of x and y. # Let's go onestep further and reconstruct # the actualsequence from DP table: def recon(i, j): if i == 0 or j ==0: return"" elif x[i-1]== y[j-1]: return recon(i-1, j-1)+ str(x[i-1]) elif table[i-1, j] > table[i, j-1]: return recon(i-1, j) else: return recon(i, j-1) return recon(n, m)
A 2D table is used in the code, and table (I, j) represents the lcs_len Of The subproblem (I, j). After analysis, its value may only be a table (I-1, j-1), table (I, J-1), table (I-1, j) One, so from top to bottom, from left to right assignment does not appear table (I, j) the assignment is not possible. Of course, obtaining lcs_len is not our ultimate goal, especially in applications. Generally, we need to obtain this LCS, so we can obtain the result through table (see the code ).
1.2.2.4 rolling array-space optimization
The process of solving this problem can be seen as the process of filling the matrix table from top to bottom, from left to right, so its time and space complexity is O (n ^ 2 ). If time complexity is still mentioned, the space complexity cannot be tolerated. The stack space of a process is about several Mb, imagine n = 1024 (this length is not too long). If each element has 4 bytes, the matrix consumes 4 MB of stack space. If such a function is used in a system, it is very dangerous to implement other functions, which may cause system crash. So how to optimize it?
In fact, in the calculation process, table [I, j] only depends on three values: Table [I-1, J-1], table [I-, J] Table [I, J-1], therefore, we only need two layers of table [2] [N]. When we want to read and write data to row I, we only need to use the subscript I % 2. In this way, the space complexity is reduced to O (n)
def lcs_dp_v1(x, y): n = len(x) m = len(y) table = dict() # a hashtable, but we'll use it as a 2Darray here for i in range(n+1): # i=0,1,...,n for j in range(m+1): # j=0,1,...,m if i== 0or j ==0: table[i%2, j]= 0 elif x[(i-1+2)%2]== y[j-1]: table[i, j]= table[(i-1+2)%2, j-1]+ 1 else: table[i, j]= max(table[(i-1+2)%2, j], table[i, j-1]) return table[n%2,m]
One detail in the code should be noted that it is very dangerous to take (I-1) % 2 directly, so it needs to be converted to (I-1 + 2) % 2 for protection.
1.2.3 edited distance 1.2.3.1 Problem Description
The distance between two strings is equal to (1) Insert, (2) Delete, (3) replace, or (4) convert a string into another string) the minimum number of operations performed on adjacent character exchanges.
1.2.3.2 recursive relationship
1. if I = 0 or J = 0:
Ed [I] [J] = max (I, j)
2. If I <= 1 or j <= 1:
Ed [I] [J] = min (edit (I-1, j) + 1, edit (I, J-1) + 1, edit (I-1, J-1) + f (I, j ))
3. If I> = 2 and j> = 2 and S1 [I-1] = S2 [J-2] ands1 [I-2] = S2 [J-1]:
Ed [I] [J] = min (edit (I-1, j) + 1, edit (I, J-1) + 1, edit (I-1, J-1) + f (I, j), edit (I-2, J-2) + 1)
At first glance, it is a bit complicated. In fact, its idea is similar to LCS. The process is to fill a two-dimensional matrix, but here we need to save three layers of data.
1.2.3.3 O (N ^ 2) Implementation
def edited_distance(s1,s2): mat = {} for i in range(0,len(s1)+1): for j in range(0,len(s2)+1): if i==0or j==0: mat[i,j]= i+j continue mat[i,j]= mat[i-1,j-1]+ int(s1[i-1]!=s2[j-1]) if mat[i,j]> mat[i-1,j]+1: mat[i,j]= mat[i-1,j]+1 if mat[i,j]> mat[i,j-1]+1: mat[i,j]= mat[i,j-1]+1 if i>=2and j>=2and s1[i-2]==s2[j-1]and s1[i-1]==s2[j-2]and mat[i,j]>mat[i-2,j-2]+1: mat[i,j]= mat[i-2,j-2]+1 return mat[len(s1),len(s2)]
1.2.3.4 Optimization
First, the space can be optimized according to the rolling array mentioned in LCS. Second, there is an implicit problem in the editing distance, that is, in generating a two-dimensional matrix, an element must be smaller than the element in the lower right corner of the adjacent table. The specific derivation is skipped. As for its usefulness, if we want to implement a search based on a certain threshold (for example, if the editing distance exceeds 5, we do not need to calculate it again), it will accelerate a lot of time.
The following code provides space optimization:
def edited_distance_v1(s1,s2): mat = {} s1 = s1.decode("utf8") s2 = s2.decode("utf8") for i in range(0,len(s1)+1): for j in range(0,len(s2)+1): if i==0 or j==0: mat[i%3,j] = i+j continue mat[i%3,j] = mat[(i-1+3)%3,j-1] + int(s1[i-1]!=s2[j-1]) if mat[i%3,j] > mat[(i-1+3)%3,j]+1: mat[i%3,j] = mat[(i-1+3)%3,j]+1 if mat[i%3,j] > mat[i%3,j-1]+1: mat[i%3,j] = mat[i%3,j-1]+1 if i>=2 and j>=2 and s1[(i-2+3)%3]==s2[j-1] and s1[i-1]==s2[j-2] and mat[i%3,j]>mat[(i-2+3)%3,j-2]+1: mat[i%3,j] = mat[(i-2+3)%3,j-2]+1 return mat[len(s1)%3,len(s2)]
1.2.4 backpack problem 1.2.4.1 Problem Description
This is a complete NP problem for combined optimization. The problem can be described as: Given a group of items, each item has its own weight and price. Within the limited total weight, how can we choose to make the total price of the item the highest.
1.2.4.2 recursive relationship
Among them, DP [I, j] indicates the maximum value that can be generated when the previous I items are loaded into a backpack with a capacity of J:
If (W [I]> J)
DP [I, j] = DP [I-1, J]
Else
DP [I, j] = max (DP [I-1, J-W [I] + V [I], DP [I-1, J]) // whether or not I is required
1.3 O (N ^ 3) problem 1.3.1 Post Office site selection 1.3.1.1 Problem Description
There are some villages (in a straight line) around a street, and some post offices need to be set up in these villages (at most one in a village ), the minimum distance from each village to the nearest post office.
1.3.1.2 recurrence relationship:
State transition equation: DP [I] [J] indicates the optimal solution of the first post office in the first J villages.
DP [I] [J] = min (DP [I-1] [k] + cost [k + 1] [J]) I-1 = <k <= J-1
# Include <stdio. h> int V, p; int position [310]; int getcost (int I, Int J) // create a minimum post office path and {int sum = 0 between village I and j; while (I <j) {sum + = (position [j --]-position [I ++]);} return sum;} int main (){... For (j = 1; j <= V; j ++) DP [1] [J] = getcost (1, J); for (I = 2; I <= P; I ++) {for (j = I; j <= V; j ++) {minsum = 0x7fffffff; For (k = I-1; k <= J-1; k ++) {minsum = (minsum> DP [I-1] [k] + getcost (k + 1, J ))? DP [I-1] [k] + getcost (k + 1, J): minsum;} DP [I] [J] = minsum ;}} printf ("% d ", DP [p] [v]); Return 0 ;}
1.3.2 Short Circuit