所有后缀的最长前缀字符串长度
Longest prefix string length for all the suffixes
为字符串的所有后缀查找最长前缀字符串的长度。
例如,字符串ababaa
的后缀为ababaa
、babaa
、abaa
、baa
、aa
和a
。这些字符串中的每一个与字符串"ababaa"的相似性分别为6,0,3,0,1,1。因此,答案是6+0+3+0+1+1=11。
我写了以下代码
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <time.h>
int main ( int argc, char **argv) {
size_t T;
std::cin >> T;
char input[100000];
for ( register size_t i = 0; i < T; ++i) {
std::cin >> input;
double t = clock();
size_t len = strlen(input);
char *left = input;
char *right = input + len - 1;
long long sol = 0;
int end_count = 1;
while ( left < right ) {
if ( *right != ' ') {
if ( *left++ == *right++ ) {
sol++;
continue;
}
}
end_count++;
left = input; // reset the left pointer
right = input + len - end_count; // set right to one left.
}
std::cout << sol + len << std::endl;
printf("time= %.3fsn", (clock() - t) / (double)(CLOCKS_PER_SEC));
}
}
工作正常,但对于一个长为100000
且具有相同字符(即aaaaaaaaaa.......a
)的字符串,它需要很长时间,我如何才能进一步优化它。
您可以使用后缀数组:http://en.wikipedia.org/wiki/Suffix_array
假设您的ababaa
是一个模式p。我认为你可以使用以下算法:
- 为P的所有可能后缀创建一个后缀自动机
- 使用P作为输入遍历自动机,计算到目前为止遍历的边。对于自动机的每个可接受状态,将当前边缘计数添加到总和中。遍历自动机,直到到达输入的末尾,或者没有更多的边可以通过
- 总和就是结果
使用Z
算法计算所有子字符串的长度,这些子字符串也在O(n)
中加前缀,然后扫描得到的数组并对其值求和。
参考:https://www.geeksforgeeks.org/sum-of-similarities-of-string-with-all-of-its-suffixes/
据我所见,您正在使用纯数组来计算后缀,尽管它可能对某些数据集有效,但在某些情况下却无法有效,例如您提到的情况。
您需要实现前缀树或类似Trie的数据结构。这些代码并不简单,所以如果你不熟悉它们,我建议你读一点关于它们的知识。
我不确定Trie是否会给您带来很大的性能提升。。但我肯定会考虑的。
我的另一个想法是尝试压缩你的字符串。我真的没想过,只是一个疯狂的想法。。。
如果您有这样一个字符串:ababaa
,则可能将其压缩为:abab2a
。然后你必须想出一种技术,你可以用你的算法处理这些字符串。这样做的好处是可以有效地比较长字符串100000a
。或者更重要的是:你可以很快地计算出你的总和。
但是,我没有仔细考虑,也许这是一个非常糟糕的主意;)
这里是一个java实现:
// sprefix
String s = "abababa";
Vector<Integer>[] v = new Vector[s.length()];
int sPrefix = s.length();
v[0] = new Vector<Integer>();
v[0].add(new Integer(0));
for(int j = 1; j < s.length(); j++)
{
v[j] = new Vector<Integer>();
v[j].add(new Integer(0));
for(int k = 0; k < v[j - 1].size(); k++)
if(s.charAt(j) == s.charAt(v[j - 1].get(k)))
{
v[j].add(v[j - 1].get(k) + 1);
v[j - 1].set(k, 0);
}
}
for(int j = 0; j < v.length; j++)
for(int k = 0; k < v[j].size(); k++)
sPrefix += v[j].get(k);
System.out.println("Result = " + sPrefix);
- 定义宏以将前缀 0x 添加到十六进制字符串文本
- 高效的字符串截断算法,按顺序删除相等的前缀和后缀
- 目标是找到两个 c 字符串之间的公共前缀(必须使用特定的函数标头)
- 我需要在C++的两个字符串之间找到共同的前缀
- 如果我有很多具有相似前缀的字符串,是否有理由从该前缀创建一个子字符串?
- 提升精神解析字符串以前缀开头
- C 11正则表达式和字符串U8前缀
- 如何实现将前缀与字符串匹配的最快算法
- 为带有带前缀的字符串的容器查找相等的范围
- 使用std :: quare_range查找字符串向量中发生的前缀范围
- 在 Python 中'r'带有字符串的前缀等效C++是多少?
- 创建一个从前缀到C 中字符位置的新字符串
- 字符文字与字符串字面的u前缀有什么区别
- 当带前缀的字符串与无前缀的字符串相邻时,字符串文本串联失败
- 一种在检查十六进制前缀后将字符串转换为int的更干净的方法
- 查找有序STL容器中以前缀开头的所有字符串(非低位ASCII)
- 为包含通用字符名的字符串文字省略u8前缀
- 进行字符串前缀测试的优雅方法
- 什么是 C# @ 符号前缀字符串的C++等效项
- 所有后缀的最长前缀字符串长度