类别 字符串处理 时间限制 1S 内存限制 256Kb 问题描述 最长公共子串指给定的两个字符串之间最长的相同子字符串(忽略大小写),最长公共子串长度可用来定义字符串相似度。 现给出两个字符串S1和S2,S1的长度为Len1,S2的长度为Len2,假设S1和S2的最长公共子串长度为LCS,则两个字符串的相似度定义为2*LCS/(Len1+Len2)。 例如:S1=”App”,S2=”apple”,S1长度为3,S2长度为5,它们的最长公共子串为”App”,长度为3,则相似度为2*3/(3+5)=0.75。 现给出两个字符串,请计算它们的相似度结果保留3位小数。 输入说明 输入为两行,分别表示两个字符串S1和S2,每个字符串长度不超过100个字符,所有字符均为可打印字符,包括大小写字母,标点符号和空格。 输出说明 输出两个字符串的相似度,结果四舍五入保留3位小数。 输入样例 App Apple 输出样例 0.750
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int iper(char *s1, char *s2){
int length1 = strlen(s1);
int length2 = strlen(s2);
int dp[length1][length2];
int result = 0;
for(int i = 0; i < strlen(s1); i++) {
s1[i] = tolower(s1[i]);
}
for(int i = 0; i < strlen(s2); i++) {
s2[i] = tolower(s2[i]);
}
memset(dp, 0, sizeof(dp));
for(int i = 0; i < length1; i++){
for(int j = 0; j < length2; j++){
if(s1[i] == s2[j]){
dp[i][j] = (i == 0 || j == 0) ? 1 : dp[i - 1][j - 1] + 1;
if(dp[i][j] > result){
result = dp[i][j];
}
}
}
}
double f = 2.0 * result / (length1 + length2);
printf("%.3lf", f);
}
int main() {
char m1[100],m2[100];
fgets(m1, sizeof(m1), stdin);
fgets(m2, sizeof(m2), stdin);
m1[strcspn(m1,"\n")] = 0;
m2[strcspn(m2,"\n")] = 0;
iper(m1,m2);
return 0;
}
for循环部分可能稍微有点难理解,让我们以两个字符串 s1 = "ABCBDAB" 和 s2 = "BDCAB" 为例,来说明这段代码的工作原理。我们将使用动态规划数组 dp 来存储最长公共子串的长度,并通过一个表格来可视化这个过程。
初始状态
首先,初始化 dp 数组。由于我们从索引0开始,dp[i][j] 将代表以 s1[i] 和 s2[j] 结尾的最长公共子串长度。初始时,所有值都设为0。
| B | D | C | A | B | ||
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | |
| A | 0 | |||||
| B | 0 | |||||
| C | 0 | |||||
| B | 0 | |||||
| D | 0 | |||||
| A | 0 | |||||
| B | 0 |
动态规划过程
我们逐个检查 s1 的每个字符(A、B、C、B、D、A、B)与 s2 的每个字符(B、D、C、A、B),并更新 dp 数组:
-
当我们在
s1的 'A' (索引0) 和s2的 'A' (索引3) 找到匹配时,dp[0][3]被更新为1(因为它们是字符串的开始部分)。 -
接下来,当
s1的 'B' (索引1) 和s2的 'B' (索引0 和 4) 找到匹配时,我们更新dp[1][0]和dp[1][4]为1。 -
这个过程持续进行,每次发现匹配时,我们根据
dp[i - 1][j - 1] + 1来更新dp[i][j]。
完成这个过程后,dp 数组如下所示:
| B | D | C | A | B | ||
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | |
| A | 0 | 0 | 0 | 0 | 1 | 0 |
| B | 0 | 1 | 0 | 0 | 0 | 2 |
| C | 0 | 0 | 0 | 1 | 0 | 0 |
| B | 0 | 1 | 0 | 0 | 0 | 2 |
| D | 0 | 0 | 1 | 0 | 0 | 0 |
| A | 0 | 0 | 0 | 0 | 1 | 0 |
| B | 0 | 1 | 0 | 0 | 0 | 2 |
结果
在这个例子中,最长公共子串的长度是2(例如,在 s1 的第二个 'B' 和 s2 的第五个 'B' 处,即 dp[4][4])。因此,最长公共子串是 "AB",长度为2。这就是 result 的最终值。
注意:在这个表格中,每个匹配都增加了左上方邻近单元格的值。例如,dp[4][4] 是2,因为它增加了 dp[3][3](值为1)的基础上。

被折叠的 条评论
为什么被折叠?



