当前位置:网站首页>[question brushing diary] classic questions of dynamic planning
[question brushing diary] classic questions of dynamic planning
2022-07-02 20:40:00 【Bai Chen is not very able to stay up late】
Hello everyone , I am a Bai Chen , One is not very able to stay up late , But people who want to be more and more . If you like this article , Point a praise , Pay attention to it. Bai Chen bar ! Your support is my biggest motivation !

List of articles
Preface
Reminders before watching : This article needs some foundation of Dynamic Planning
Most methods of dynamic programming are very abstract , And it has a wide range of applications in life . The abstraction of this algorithm requires learning dynamic programming algorithm , You can't just look at the idea of the algorithm , Instead of doing questions .
therefore , Bai Chen sorted out the classic topics in dynamic programming for everyone to better master the dynamic programming algorithm , Topics range from matrix to string , The difficulty goes from easy to difficult , The degree of abstraction ranges from one dimension to two dimensions .
If you haven't been exposed to the idea of Dynamic Planning perhaps Some of the questions are really hard to understand It doesn't matter , Bai Chen will release the full analysis of dynamic programming algorithm in the near future , Among them, it focuses on the more difficult topics in dynamic planning again , Such as knapsack problem .
Dynamic programming classic topic
1. Fibonacci sequence

Original link : Fibonacci sequence
This problem may be a problem that you have just learned C A problem I did when I was speaking , Now let's analyze this problem according to the idea of dynamic programming :
What is the state of this problem ?
That is, we need to solve / Face what , What we need to solve here is the Fibonacci number n Value of item , So we set the first n Item value is f ( n ) f(n) f(n) , That is, the status is f ( n ) f(n) f(n)
What is the state transition equation ?
Here we can analyze the state , use
Where do I come fromThe idea of , It's easy to get f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n) = f(n - 1) + f(n - 2) f(n)=f(n−1)+f(n−2) .What is the initialization of state ?
That is, what is the initial state ?
f ( 1 ) = 1 , f ( 2 ) = 1 f(1) = 1 , f(2) = 1 f(1)=1,f(2)=1
Return value
From the above, we can get that the return value is f ( n ) f(n) f(n) .
To sum up :
- state : f ( k ) f(k) f(k)
- State recurrence : f ( k ) = f ( k − 1 ) + f ( k − 2 ) f(k) = f(k - 1) + f(k - 2) f(k)=f(k−1)+f(k−2)
- Initial value : f ( 1 ) = f ( 2 ) = 1 f(1) = f(2) = 1 f(1)=f(2)=1
- Return results : f ( n ) f(n) f(n)
According to the above analysis, the specific code :
class Solution {
public:
int Fibonacci(int n) {
int fib1 = 1;
int fib2 = 1;
int f;
if (n == 1 || n == 2)
return 1;
for (int i = 3; i <= n; i++)
{
f = fib1 + fib2;
fib2 = fib1;
fib1 = f;
}
return f;
}
};
2. Split words and sentences

Original link : Split words and sentences
state :
Substate : front 1,2,3,…,n Whether a character can be successfully segmented according to the words in the dictionary
- F ( i ) F(i) F(i) : front
iWhether a character can be successfully segmented according to the words in the dictionaryState recurrence :
- F ( i ) F(i) F(i): true{$j < i $ && F ( j ) F(j) F(j) && s u b s t r [ j + 1 , i ] substr[j+1,i] substr[j+1,i] Can be found in a dictionary } OR false
- stay
jLess thaniin , As long as you can find one F ( j ) F(j) F(j) by true, And fromj+1ToiThe characters between can be found in the dictionary , be F ( i ) F(i) F(i) by trueInitial value :
- For those whose initial value cannot be determined , You can introduce an empty state that does not represent the actual meaning , As the beginning of the State ;
- The value of empty state needs to ensure that the state recurrence can be carried out correctly and smoothly , What value to take can be verified by a simple example
- F ( 0 ) = t r u e F(0) = true F(0)=true
Return results : F ( n ) F(n) F(n)
class Solution {
public:
bool wordBreak(string s, unordered_set<string>& dict) {
if (s.empty())
return false;
if (dict.empty())
return false;
vector<bool> can_spe(s.size() + 1, false);
// initialization
can_spe[0] = true;
for (int i = 1; i <= s.size(); i++)
{
for (int j = i - 1; j >= 0; j--)
{
// At present j Characters can be separated from a dictionary , also [j + 1, i] When the character of is exactly the character in the dictionary
// Judge as true
if (can_spe[j] && dict.find(s.substr(j, i - j)) != dict.end())
{
can_spe[i] = true;
break;
}
}
}
return can_spe[s.size()];
}
};
3. Trigonometric matrix

Original link : triangle


class Solution {
public:
int minimumTotal(vector<vector<int> >& triangle) {
if (triangle.empty())
return 0;
int row = triangle.size();
for (int i = 1; i < row; i++)
{
for (int j = 0; j <= i; j++)
{
// initialization
if (j == 0)
triangle[i][0] = triangle[i - 1][0] + triangle[i][0];
else if (j == i)
triangle[i][j] = triangle[i - 1][j - 1] + triangle[i][j];
// Choose to arrive [i][j] The minimum value of
else
triangle[i][j] = min(triangle[i - 1][j], triangle[i - 1][j - 1]) + triangle[i][j];
}
}
int Min = triangle[row - 1][0];
// Traverse the last line , Select the minimum value
for (int j = 1; j < row; j++)
Min = min(Min, triangle[row - 1][j]);
return Min;
}
};
4. Find the way

Original link : Find the way
Law 1 : recursive
class Solution {
public:
int uniquePaths(int m, int n) {
if (m == 1 || n == 1)
return 1;
return uniquePaths(m - 1, n) + uniquePaths(m, n - 1);
}
};
Law two : Dynamic programming

class Solution {
public:
int uniquePaths(int m, int n) {
if (m == 1 || n == 1)
return 1;
// Initialize to 1
vector<vector<int> > a(m, vector<int>(n, 1));
for (int i = 1; i < m; i++)
{
// arrive [i][j] The number of paths be equal to arrive [i - 1][j] And arrival [i][j - 1] The sum of the number of paths
for (int j = 1; j < n; j++)
a[i][j] = a[i][j - 1] + a[i - 1][j];
}
return a[m - 1][n - 1];
}
};
Law three : Formula method

class Solution {
public:
int uniquePaths(int m, int n) {
long long ret = 1;
for (int i = n, j = 1; j < m; i++, j++)
ret = ret * i / j;
return ret;
}
};
5. Minimum path sum with weight

Original link : Minimum path sum with weight


class Solution {
public:
int minPathSum(vector<vector<int> >& grid) {
int m = grid.size();
int n = grid[0].size();
// initialization
for (int i = 1; i < m; i++)
grid[i][0] = grid[i - 1][0] + grid[i][0];
for (int i = 1; i < n; i++)
grid[0][i] = grid[0][i - 1] + grid[0][i];
// Transfer equation
for (int i = 1; i < m; i++)
{
for (int j = 1; j < n; j++)
grid[i][j] = min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j];
}
return grid[m - 1][n - 1];
}
};
🧂6. knapsack problem

Original link : knapsack problem

class Solution {
public:
int backPackII(int m, vector<int>& A, vector<int>& V) {
if (A.empty() || V.empty() || m < 1)
return 0;
const int N = A.size() + 1;
const int M = m + 1;
vector<vector<int> > ret;
ret.resize(N);
// initialization
for (int i = 0; i != N; ++i) {
ret[i].resize(M, 0);
}
for (int i = 1; i < N; i++)
{
for (int j = 1; j < M; j++)
{
// If the total space of the backpack is not enough i Items , Then put i Items and discharge i - 1 The situation of two items is the same
if (j < A[i - 1])
ret[i][j] = ret[i - 1][j];
// If there's enough room for i Items , Then it is necessary to judge whether to put , See the above analysis for details
else
ret[i][j] = max(ret[i - 1][j], ret[i - 1][j - A[i - 1]] + V[i - 1]);
}
}
return ret[N - 1][m];
}
};
optimization algorithm :
class Solution {
public:
int backPackII(int m, vector<int>& A, vector<int>& V) {
if (A.empty() || V.empty() || m < 1)
return 0;
const int M = m + 1; // Package capacity
const int N = A.size() + 1; // Quantity of articles
vector<int> ret(M, 0);
for (int i = 1; i < N; i++)
{
// The above algorithm is calculating the i Line element , Only the second i-1 Elements of the line , Therefore, two-dimensional space can be optimized into one-dimensional space
// But if it's a one-dimensional vector , Need to calculate from back to front , Because the later element update needs to rely on the previous element not updated ( Simulate the value of the upper row of a two-dimensional matrix )
// And we observed , The elements of this line only need to use the elements of the previous line , So from front to back , It's the same from back to front
// And the subscript of the element in the previous line will not exceed the subscript of the element in this line
for (int j = m; j >= 0; j--)
{
if (j >= A[i - 1])
ret[j] = max(ret[j], ret[j - A[i - 1]] + V[i - 1]);
}
}
return ret[m];
}
};
7. Split palindrome string

Original link : Split palindrome string
state :
Substate : To the first 1,2,3,…,n The minimum number of divisions required for a character
- F ( i ) F(i) F(i): To the first i The minimum number of divisions required for a character
State recurrence :
- F ( i ) = m i n F ( i ) , 1 + F ( j ) F(i) = min{F(i), 1 + F(j)} F(i)=minF(i),1+F(j), where j < i && j + 1 To i It's a palindrome string
- The above formula means if from j+1 To i It is a palindrome string , And already know from the 1 Character to character j Minimum number of cuts of characters , Then just cut it again , You can guarantee 1–>j, j+1–>i Are palindromes .
initialization :
- F ( i ) = i − 1 F(i) = i - 1 F(i)=i−1
- The above formula means to i The maximum number of divisions required for a character , For example, a single character only needs to be cut 0 Time , Because the list characters are palindromes ,2 Characters, max 1 Time ,3 individual 2 Time …
Return results :
- F ( n ) F(n) F(n)
class Solution {
public:
// Determine whether it is a palindrome string
bool isPal(string& s, int left, int right)
{
while (left < right)
{
if (s[left] != s[right])
return false;
left++;
right--;
}
return true;
}
int minCut(string s) {
if (s.empty())
return 0;
int len = s.size();
int* ret = new int[len + 1];
// One is long for i String , Form palindrome string , At most, it needs to be cut i - 1 The knife
for (int i = 0; i <= len; ++i)
{
// Initialize to the maximum number of times each string can be divided
ret[i] = i - 1;
}
for (int i = 2; i <= len; ++i)
{
for (int j = 0; j <= i; j++)
{
// Judge j + 1 To i Whether the string of is a palindrome string
if (isPal(s, j, i - 1))
ret[i] = min(ret[i], ret[j] + 1);
}
}
return ret[len];
}
};
The above method Time complexity of two cycles yes O ( n 2 ) O(n ^ 2) O(n2) , Determine the time complexity of palindrome string yes O ( n ) O(n) O(n) , therefore Total time complexity by O ( n 3 ) O(n ^ 3) O(n3) .
For long strings , stay OJ When it comes to TLE(Time Limit Exceeded), The method of judging palindrome string can continue to be optimized , The overall time complexity will be O ( n 2 ) O(n^2) O(n2) .
Judging palindrome string , This is a “ Is it right? ” The problem of , So it can also be realized by dynamic programming
state :
Substate : Is the palindrome string from the first character to the second character , The first 1-3, The first 2-5,…
- F ( i , j ) F(i,j) F(i,j): Character range [i,j] Whether it is palindrome string
State recurrence :
- F ( i , j ) F(i,j) F(i,j): true->{ s [ i ] = = s [ j ] s[ i ]==s[j] s[i]==s[j] && F ( i + 1 , j − 1 ) F(i+1,j-1) F(i+1,j−1)} OR false
The above formula indicates that if the first and last characters of the character interval are the same, and after removing the first and last characters of the interval, the character interval is still a palindrome string , Then the original character interval is palindrome string- From the recurrence formula, we can see that i You need to use the second i + 1 The information in the office , therefore i You should traverse... From the end of the string
initialization :
F ( i , j ) F(i,j) F(i,j) = falseReturn results :
matrix F ( n , n ) F(n,n) F(n,n), Update only half the value (i <= j),$n^2 / 2 $
class Solution {
public:
vector<vector<bool> > getMat(string& s)
{
int len = s.size();
vector<vector<bool> > mat = vector<vector<bool> >(len, vector<bool>(len, false));
for (int i = len - 1; i >= 0; --i)
{
// Judge [i , j] Whether it is palindrome within the scope
for (int j = i; j < len; ++j)
{
if (j == i)
mat[i][j] = true;
else if (j == i + 1)
mat[i][j] = (s[i] == s[j]);
else
mat[i][j] = ((s[i] == s[j]) && mat[i + 1][j - 1]);
}
}
return mat;
}
int minCut(string s) {
if (s.empty())
return 0;
int len = s.size();
int* ret = new int[len + 1];
// Get palindrome string judgment array
vector<vector<bool> > mat = getMat(s);
// One is long for i String , Form palindrome string , At most, it needs to be cut i - 1 The knife
for (int i = 0; i <= len; ++i)
{
ret[i] = i - 1;
}
for (int i = 2; i <= len; ++i)
{
for (int j = 0; j <= i; ++j)
{
// Now judge j + 1 To i Whether the string of is a palindrome string , You can get it directly from the array
if (mat[j][i - 1])
ret[i] = min(ret[i], ret[j] + 1);
}
}
return ret[len];
}
};
Sum up , The time complexity of this algorithm is optimized to O ( n 2 ) O(n^2) O(n2)
8. Edit distance

Original link : Edit distance
state :
word1Before1,2,3,...mConvert characters toword2Before1,2,3,...nEdit distance required for characters
- F ( i , j ) F(i,j) F(i,j):
word1BeforeiCharacters inword2BeforejEdit distance of charactersState recurrence :
- F ( i , j ) = m i n F ( i − 1 , j ) + 1 , F ( i , j − 1 ) + 1 , F ( i − 1 , j − 1 ) + ( w 1 [ i ] = = w 2 [ j ] ? 0 : 1 ) F(i,j) = min { F(i-1,j)+1, F(i,j-1) +1, F(i-1,j-1) +(w1[i]==w2[j]?0:1) } F(i,j)=minF(i−1,j)+1,F(i,j−1)+1,F(i−1,j−1)+(w1[i]==w2[j]?0:1)
The above formula means to delete , Select a minimum operand in the add and replace operations
- F ( i − 1 , j ) F(i-1,j) F(i−1,j): w 1 [ 1 , . . . , i − 1 ] w1[1,...,i-1] w1[1,...,i−1] On w 2 [ 1 , . . . , j ] w2[1,...,j] w2[1,...,j] Editor's distance , Delete w 1 [ i ] w1[i] w1[i] The characters of —> F ( i , j ) F(i,j) F(i,j)
- F ( i , j − 1 ) F(i,j-1) F(i,j−1): w 1 [ 1 , . . . , i ] w1[1,...,i] w1[1,...,i] On w 2 [ 1 , . . . , j − 1 ] w2[1,...,j-1] w2[1,...,j−1] Editor's distance , Add a character —> F ( i , j ) F(i,j) F(i,j)
- F ( i − 1 , j − 1 ) F(i-1,j-1) F(i−1,j−1): w 1 [ 1 , . . . , i − 1 ] w1[1,...,i-1] w1[1,...,i−1] On w 2 [ 1 , . . . , j − 1 ] w2[1,...,j-1] w2[1,...,j−1] Editor's distance , If w 1 [ i ] w1[i] w1[i] And w 2 [ j ] w2[j] w2[j] identical , Do nothing , Edit distance unchanged , If w 1 [ i ] w1[i] w1[i] And w 2 [ j ] w2[j] w2[j] Different , Replace w 1 [ i ] w1[i] w1[i] The character of is w 2 [ j ] w2[j] w2[j]—> F ( i , j ) F(i,j) F(i,j)
initialization :
Initialization must be a certain value , If you add an empty string here , To determine the initialization status
- F ( i , 0 ) = i F(i,0) = i F(i,0)=i :word Edit distance from empty string , Delete operation
- F ( 0 , i ) = i F(0,i) = i F(0,i)=i : Empty string and word Editor's distance , Increase the operating
Return results : F ( m , n ) F(m,n) F(m,n)
class Solution {
public:
int minDistance(string word1, string word2) {
if (word1.empty() || word2.empty())
return max(word1.size(), word2.size());
int len1 = word1.size();
int len2 = word2.size();
vector<vector<int>> ret(len1 + 1, vector<int>(len2 + 1, 0));
// initialization
// j == 0 when
for (int i = 0; i <= len1; ++i)
ret[i][0] = i;
// i == 0 when
for (int i = 0; i <= len2; ++i)
ret[0][i] = i;
for (int i = 1; i <= len1; ++i)
{
for (int j = 1; j <= len2; ++j)
{
// Select Delete first or Insert
ret[i][j] = min(ret[i - 1][j] + 1, ret[i][j - 1] + 1);
// Decide whether to replace , If you want to replace , Operands +1 , On the contrary, it will not change
// word1 Of the i Characters , The corresponding index is i - 1,word2 Empathy
if (word1[i - 1] == word2[j - 1])
ret[i][j] = min(ret[i - 1][j - 1], ret[i][j]);
else
ret[i][j] = min(ret[i - 1][j - 1] + 1, ret[i][j]);
}
}
return ret[len1][len2];
}
};
9. Different subsequences

Original link : Different subsequences
state :
Substate : fromSBefore1,2,...,mA substring of characters andTBefore1,2,...,nThe same number of characters
- F ( i , j ) F(i,j) F(i,j) :
S[0 ~ i-1]Substrings in andT[0 ~ j-1]The same numberState recurrence :
stay F ( i , j ) F(i,j) F(i,j) We need to consider S [ i − 1 ] = T [ j − 1 ] S[i - 1] = T[j - 1] S[i−1]=T[j−1] and S [ i − 1 ] ! = T [ j − 1 ] S[i - 1] != T[j - 1] S[i−1]!=T[j−1] Two cases ( hereSOf theiThe index value of characters isi - 1,TEmpathy )
- When S [ i − 1 ] = T [ j − 1 ] S[i-1] = T[j-1] S[i−1]=T[j−1]:
- Give Way S [ i − 1 ] S[i - 1] S[i−1] matching T [ j − 1 ] T[j-1] T[j−1], be
F ( i , j ) = F ( i − 1 , j − 1 ) F(i,j) = F(i-1,j-1) F(i,j)=F(i−1,j−1)- Give Way S [ i − 1 ] S[i - 1] S[i−1] Mismatch T [ j − 1 ] T[j - 1] T[j−1], Then the problem becomes
S[0 ~ i-1]Substrings in andT[0 ~ j-1]The same number , be
F ( i , j ) = F ( i − 1 , j ) F(i,j) = F(i-1,j) F(i,j)=F(i−1,j)
so , S [ i − 1 ] = T [ j − 1 ] S[i-1] = T[j-1] S[i−1]=T[j−1] when , F ( i , j ) = F ( i − 1 , j − 1 ) + F ( i − 1 , j ) F(i,j) = F(i-1,j-1) + F(i-1,j) F(i,j)=F(i−1,j−1)+F(i−1,j)- When S [ i − 1 ] ! = T [ j − 1 ] S[i-1] != T[j-1] S[i−1]!=T[j−1]:
The problem degenerates intoS[0 ~ i-2]Substrings in andT[0 ~ j-1]The same number
so , S [ i − 1 ] ! = T [ j − 1 ] S[i-1] != T[j-1] S[i−1]!=T[j−1] when , F ( i , j ) = F ( i − 1 , j ) F(i,j) = F(i-1,j) F(i,j)=F(i−1,j)initialization : Introduce an empty string for initialization
- F ( i , 0 ) = 1 F(i,0) = 1 F(i,0)=1 —> S The number of substrings is the same as that of empty strings , Only an empty string is the same as an empty string
Return results :
F ( m , n ) F(m,n) F(m,n)
class Solution {
public:
int numDistinct(string S, string T) {
int lenS = S.size();
int lenT = T.size();
vector<vector<int> > ret(lenS + 1, vector<int>(lenT + 1, 0));
// initialization
for (int i = 0; i <= lenS; ++i)
ret[i][0] = 1;
for (int i = 1; i <= lenS; ++i)
{
for (int j = 1; j <= lenT; ++j)
{
// Judge S Of the i Whether the characters are the same as T Of the j The characters are equal
// If equal , You can choose whether to use S Of the i Characters , The final result is Use S Of the i Characters + not used S Of the i Characters
// If it's not equal , Just inherit S Before i - 1 Characters And T Before j Characters The same number
if (S[i - 1] == T[j - 1])
ret[i][j] = ret[i - 1][j] + ret[i - 1][j - 1];
else
ret[i][j] = ret[i - 1][j];
}
}
return ret[lenS][lenT];
}
};
We observed that r e t [ i , j ] ret[i , j] ret[i,j] The value of is only related to r e t [ i − 1 , j ] ret[i - 1, j] ret[i−1,j] and r e t [ i − 1 , j − 1 ] ret[i - 1,j -1] ret[i−1,j−1] of , So we can use optimization methods similar to knapsack problem , Optimize the space complexity to O ( n ) O(n) O(n) .
optimization algorithm :
class Solution {
public:
int numDistinct(string S, string T) {
int lenS = S.size();
int lenT = T.size();
// Just keep the columns
vector<int> ret(lenT + 1, 0);
ret[0] = 1;
for (int i = 1; i <= lenS; ++i)
{
// In order to prevent the value of the previous line from being overwritten before it is used , We must go the other way , From the last column to the first column
for (int j = lenT; j >= 1; --j)
{
if (S[i - 1] == T[j - 1])
ret[j] = ret[j] + ret[j - 1];
else
ret[j] = ret[j];
}
}
return ret[lenT];
}
};
summary
Dynamic programming state definition
Status source : Abstract the state from the problem
Abstract state : Each state corresponds to a sub problem
There are many definitions of state , But what about verifying the rationality of the state definition ?
- Can the solution of a certain state or the solution after multiple states processing correspond to the solution of the final problem .
- Recursive relationships can be formed between States .
One dimensional state or Two dimensional state ?
Find clues according to the subject .
First try the one-dimensional state , When the one-dimensional state is unreasonable , Then define the two-dimensional state .
Status of frequently asked questions :
- character string : The state generally corresponds to the substring , A new character is usually added in the state each time .
- matrix : Two dimensional state ( When only the data of the previous row is used , It may be optimized into a one-dimensional state )
Be careful : In dynamic programming , The most important step is to define the state , If the state definition is unreasonable , There will be a lot of trouble .
This is a new series ——【 Writing diary 】, The original intention of Bai chenkai's series is to share some classic questions , So that we can better learn programming .
If there is something wrong with the parsing, please correct it , I'll change it as soon as possible , Thank you for your tolerance .
If you like this series , Please give us more support !
If this article helps you , Please also give me one The thumb and Little star ️ Give me your support ! Like Bai Chen 【 Writing diary 】 Series words , Not as good as Focus on Bai Chen , To see the latest updates !!!
I can't stay up late in the morning , See you in the next article .
边栏推荐
- Research Report on the overall scale, major manufacturers, major regions, products and applications of battery control units in the global market in 2022
- Don't you want to have a face-to-face communication with cloud native and open source experts? (including benefits
- Why do I have a passion for process?
- 功能、作用、效能、功用、效用、功效
- Research and Analysis on the current situation of China's clamping device market and forecast report on its development prospect
- Redis sentinel cluster working principle and architecture deployment # yyds dry goods inventory #
- Welfare | Hupu isux11 Anniversary Edition is limited to hand sale!
- esp32c3 crash分析
- Research Report on the overall scale, major manufacturers, major regions, products and applications of friction dampers in the global market in 2022
- Resunnet - tensorrt8.2 Speed and Display record Sheet on Jetson Xavier NX (continuously supplemented)
猜你喜欢

【实习】解决请求参数过长问题

外包干了三年,废了...

CS5268完美代替AG9321MCQ Typec多合一扩展坞方案

Customized Huawei hg8546m restores Huawei's original interface

Attack and defense world PWN question: Echo

Interested parties add me for private chat

Postman interface test practice, these five questions you must know

Roommate, a king of time, I took care of the C language structure memory alignment
![[fluent] dart technique (independent main function entry | nullable type determination | default value setting)](/img/cc/3e4ff5cb2237c0f2007c61db1c346d.jpg)
[fluent] dart technique (independent main function entry | nullable type determination | default value setting)

Internal/validators js:124 throw new ERR_ INVALID_ ARG_ Type (name, 'string', value) -- solution
随机推荐
Customized Huawei hg8546m restores Huawei's original interface
C language linked list -- to be added
Lantern Festival, come and guess lantern riddles to win the "year of the tiger Doll"!
[JS] get the search parameters of URL in hash mode
What are the preferential account opening policies of securities companies now? Is it actually safe to open an account online?
Send blessings on Lantern Festival | limited edition red envelope cover of audio and video is released!
Talk about macromolecule coding theory and Lao Wang's fallacy from the perspective of evolution theory
CRM客户关系管理系统
I want to ask you, where is a better place to open an account in Dongguan? Is it safe to open a mobile account?
【871. 最低加油次数】
Want to ask, is there any discount for opening an account now? Is it safe to open an account online?
Share several map bed websites for everyone to share pictures
八年测开经验,面试28K公司后,吐血整理出高频面试题和答案
Research Report on the overall scale, major manufacturers, major regions, products and applications of friction dampers in the global market in 2022
CRM Customer Relationship Management System
Number of DP schemes
JS modularization
How my mother-in-law and daughter-in-law get along
How to open an account online? Is it safe to open a mobile account?
Sword finger offer (II) -- search in two-dimensional array