【发布时间】:2021-05-21 21:49:43
【问题描述】:
const char *_longest_common_substr(const char *s1, const char *s2, int n, int m) {
// assert n >= m
int max = 0; // keep track of max length found
int tmp = 0; // value is incremented till letters match
int begin = 0;
int try_begin = 0; // possible new begin index
int end = 0; // rv = s2[begin : end - 1]
for (int i = 0; i < n; i++) {
tmp = 0;
try_begin = 0;
// s1 is scanned circularly
for (int j = 0; j < m; j++) {
int index = (j + i) % n; // current s1 index
if (index < n && s1[index] == s2[j]) {
if (tmp == 0)
try_begin = j;
tmp++;
} else {
tmp = 0;
}
if (tmp > max) {
max = tmp;
begin = try_begin;
end = j + 1;
}
}
}
int size = begin >= end ? 0 : end - begin;
char *rv = malloc((size + 1) * sizeof(*rv));
int i;
for (i = 0; i < size; i++)
rv[i] = s2[begin + i];
rv[i] = '\0';
return rv;
}
const char *longest_common_substr(const char *s1, const char *s2, int n, int m) {
if (n < m)
return _longest_common_substr(s2, s1, m, n);
return _longest_common_substr(s1, s2, n, m);
}
此代码是否正确找到最长的公共子字符串?我不明白为什么在很多地方,例如wikipedia,他们使用矩阵来解决问题,而在这个看似简单的解决方案中不需要它并且时间复杂度仍然是 O(n*m ),而空间复杂度为 O(1)。 一个可能的测试是
int main() {
const char *str1 = "identification";
const char *str2 = "administration";
printf("%s\n", longest_common_substr(str1, str2, strlen(str1), strlen(str2)));
}
输出是
ation
子字符串是循环的,所以输入
action
tionac
输出将是
tionac
无论如何,我可以在字符串末尾添加两个不同的无效字符来删除此属性
【问题讨论】:
-
这段代码是否正确。您应该尝试自己通过针对代码运行测试用例来回答这个问题。
-
是的,我做到了并且有效
-
您需要更好的变量名称。你的算法很难理解
-
@bolov 我添加了一些 cmets
-
_longestCommonSubstr名称保留给 C++ 中全局命名空间中的语言实现。通过定义它,程序的行为将是未定义的。您应该为该函数使用另一个名称。
标签: c algorithm time-complexity