LCS最长公共子序列
最长公共子序列(longest common sequence)和最长公共子串(longest common substring)不是一回事儿。即一个给定的序列的子序列,就是将给定序列中零个或多个元素去掉之后得到的结果。什么是子串,给定串中任意个连续的字符组成的子序列称为该串的子串。
动态规划
设Ax,Bx表示 A 和 B的连续前 x 项构成的子序列,用LCS(x,y)表示它们的最长公共子序列长度,那原问题就是求LCS(m,n)。
用$L(x,y)$表示Ax和Bx的一个最长公共子序列。
(1) Ax = By那么A和B的最长公共子序列一定是这个元素
有 LCS(x,y) = LCs(x-1,y-1) + 1
(2)$Ax\neq By$
如果 $t\neq Ax$,则有$LCS(x,y)=LCS(x-1,y)$,因为与Ax 无关了
如果$t\neq By$,则$LCS(x,y)=LCS(x,y-1)$
$LCS(x,y)=LCS(x-1,y-1)+1 (Ax=By)$
$max(LCS(x-1,y),LCS(x,y-1)) (Ax\neq By)$
$0 如果 x=0 或者 y = 0$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int N = 1010; int f[N][N]; char s1[N], s2[N]; int main() { int m,n; cin >> m >> n; cin >> s1+1 >> s2+1; f[1][0] = f[0][1] = 0; for(int i = 1;i <= m;i++) { for(int j = 1; j <= n;j++) { if(s1[i] == s2[j]) f[i][j] = f[i-1][j-1]+1; else f[i][j] = max(f[i-1][j],f[i][j-1]); } } cout << f[m][n]; return 0; }
|
L2-008 最长对称子串 (25 分)
对给定的字符串,本题要求你输出最长对称子串的长度。例如,给定Is PAT&TAP symmetric?,最长对称子串为s PAT&TAP s,于是你应该输出11。
输入格式:
输入在一行中给出长度不超过1000的非空字符串。
输出格式:
在一行中输出最长对称子串的长度。
输入样例:
Is PAT&TAP symmetric?
输出样例:
11
原文链接:https://blog.csdn.net/weixin_43264529/article/details/88812551
暴力DP
设A[l][r]为字符串 str[l:r]的最长对称子串
对于第 l 位与第 r 位之间的字符串str[l:r],如果其是对称子串的话,则满足str[l] == str[r],且str[l+1: r-1]为对称子串
初始条件
A[i][j] == 1 - > i == j
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include<isotream> using namespace std; vector<vector<int>> A(n,vector<int>(n,0)); int main() { string str = ""; getline(cin,str); int n = str.size(); for(int i = 0;i < n;i++) A[i][i] = 1; int Max = 1; for(int len = 1;len < n;len++) { for(int l = 0;l + len< n;l++) { int r = l + len; if(str[l] == str[r]) { if(A[l+1][r-1] == r - l -1) { A[l][r] = A[l+1][r-1] + 2; if(A[l][r] > Max) Max = A[l][r]; } } } } }
|
最长连续和
题目描述:给出一个长度为n的序列A1,A2,…,An,求最大连续和。换句话说,要求找到1<=i<=j<=n,使得Ai+Ai+1+…Aj尽量大。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <iostream> using namespace std; const int N = 110;
int a[N], d[N];
int main() { int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; d[1] = a[1]; for (int i = 2; i <= n; i++) { if (d[i - 1] > 0) d[i] = d[i - 1] + a[i]; else d[i] = a[i]; } cout << d[n]; return 0; }
|
examples
letcode 279.完全平方数
https://leetcode-cn.com/problems/perfect-squares/
解法一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { public: int numSquares(int n) { vector<int> dp(n + 1); dp[0] = 0; for(int i = 1; i <= n; i++){ dp[i] = i; for(int j = 1; j <= sqrt(i); j++){ dp[i] = min(dp[i], dp[i - j*j] + 1); } } return dp[n]; } };
|

解法二
遍历树的层数

</a>
把 n 看成根节点, n 减去第一个可能的完全平方数的集合就是根的子节点。当某个节点的子节点的值第一次为 0 时,说明这一层我们已经找到了数N 的组成方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class Solution { public: int numSquares(int n) { queue<int> total; set<int> visited; int step = 0; total.push(n); while(!total.empty()){ step++; int l = total.size(); for(int i = 0; i < l; i++){ int top = total.front(); total.pop(); for(int j = 1; j <= sqrt(top); j++){ int x = top - j*j; if(x == 0) return step; if(visited.find(x) == visited.end() && x > 0){ total.push(x); visited.insert(x); } } } } return n; } };
|
数塔问题 (算法笔记p427)
采用递归求法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| int f[10][10]; int n; int dp[10][10]; memset(a,-1,sizeof(dp)); int F(int i,int j){ if(dp[i][j]!=-1) return f[i][j]; if(i==n) return f[i][j]; dp[i][j]=max(F(i+1,j),F(i+1,j+1))+f[i][j]; return dp[i][j]; } int main(){ cin>>n; for(int i = 1;i<=n;++i){ for(int j = 1;j<=i;j++) { cin>>f[i][j]; } } cout<<F(1,1); return 0; }
|
自底向上递推写法
1 2 3 4 5 6 7 8
| for(int j=1;j<=n;j++){ dp[n][j] = f[n][j]; } for(int i = n-1;i>=1;i--){ for(int j=1;j<=i;j++){ dp[i][j] = max(dp[i+1][j],dp[i+1][j+1]) + f[i][j]; } }
|