文章目录
1.一个一维数组dp[]
1.1 最长上升子序列
动态规划的时间复杂度$O(n)$
二分查找:$O(nlogn)$,纸牌问题:纸牌只能摞在比他大的纸牌上,如果当前没有堆可以放,就另起一堆,如果有多个堆都能放,就放在最左边的堆。有几堆纸牌最长上升子序列的长度就是几。变相等价于,用二分查找找左边界。
if(a[mid]>=v) y=mid;
else x=mid+1;
最长上升子序列LIS
dp[i]表示以a[i]结尾的子序列最长子序列长度
从dp[i-1]推导dp[i],因为是以a[i]结尾的,所以a[i]一定在子序列里面,那么要找前面比a[i]小的数字结尾的最大子序列长度即可
连续子数组的最大和
dp[i]表示以a[i]结尾的最大连续和
这里必须是连续的,所以从dp[i-1]推导dp[i]的时候,dp[i]必须包含a[i],否则不连续,那么需要讨论的就是dp[i-1]的贡献
2.一个二维数组dp[][]
2.1涉及两个字符串
最长公共子序列LCS
int Lcs(char x[], char y[])
{
int i, j, len1 = strlen(x + 1), len2 = strlen(y + 1);//strlen(x+1)是求得从第二个字符开始到结尾的长度
memset(dp, 0, sizeof(dp));
for (i = 1; i <= len1; ++i)
for (j = 1; j <= len2; ++j)
{
if (x[i] == y[j])
dp[i][j] = dp[i - 1][j - 1] + 1, path[i][j] = 1;
else if (dp[i - 1][j] >= dp[i][j - 1])
dp[i][j] = dp[i - 1][j], path[i][j] = 2;
else
dp[i][j] = dp[i][j - 1], path[i][j] = 3;
}
return dp[len1][len2];
}
只要是让两个字符串 有“相同”之类的描述,就考虑公共子序列
可以延伸出的问题:
两个字符串的最小ASCII删除和(leetcode)
注意这道题的base case 和状态转移方程,看leetcode的注释