动态规划问题:明确「状态」 -> 定义 dp 数组/函数的含义 -> 明确「选择」-> 明确 base case。
leetcode300: 最长递增子序列.
int lengthOfLIS(int* nums, int numsSize){
//dp[i]表示以下标i结尾的数组的最长递增子序列的长度
int dp[numsSize];
//初始值:dp[i] = 1,最少都有一个数满足为递增子序列;
for(int i = 0; i < numsSize; i++)
dp[i] = 1;
//状态转移方程:dp[i-1]->dp[i]的思考过程:试想,我们现在知道了dp[i-1]的值,
//即知道了到下标i-1的最长递增子序列的长度,求下标i位置的最长递增子序列的长度?
//既然是递增子序列,我们只要找到i前面那些结尾比nums[i]小的子序列,然后把nums[i]接到最后,
//就可以形成一个新的递增子序列,而且这个新的子序列长度加一.因此,状态转移方程为遍历所有小于i的位置,
//找到:if(nums[i] > nums[j]) dp[i] = fmax(dp[i], dp[j] + 1);
for(int i = 0; i < numsSize; i++){
for(int j = 0; j < i; j++){
if(nums[i] > nums[j])
dp[i] = fmax(dp[i], dp[j] + 1);
}
}
int res = 0;
for(int i = 0; i < numsSize; i++){
if(res < dp[i])
res = dp[i];
}
return res;
}
leetcode1143:最长公共子序列.
int longestCommonSubsequence(char * text1, char * text2){
int n1 = strlen(text1);
int n2 = strlen(text2);
//定义状态方程
int dp[n1+1][n2+1];
//初始化值
for(int i = 0; i <= n1; i++){
dp[i][0] = 0;
}
for(int j = 0; j <= n2; j++){
dp[0][j] = 0;
}
for(int i = 1; i <= n1; i++){
for(int j = 1; j <= n2; j++){
dp[i][j] = 0;
int temp = fmax(dp[i-1][j], dp[i][j-1]);
//状态转移方程
if(text1[i - 1] == text2[j - 1]){
dp[i][j] = dp[i-1][j-1] + 1;
}else{ //不相等
dp[i][j] = temp;
}
}
}
return dp[n1][n2];
}