我正在尝试实现一些在多个字符串之间找到公共后缀的东西,为了便于说明,请考虑以下内容:
"The quick brown fox" "The not so quick brown fox" "The smelly brown fox" "The vicious brown fox"
对于一个人来说,很明显这里的公共后缀是" brown fox"
,我的天真实现当前采用第一对字符串,将它们都转换为char数组,然后迭代这些字符串直到一个字符为发现是不同的,然后我从中创建一个新的字符串,并将其裁剪为长度,将其反转回正确的顺序,然后返回。然后,我重复使用第一个字符串中的结果和列表中的下一个字符串。
虽然这是松散的O(N),但这并不像我想的那样好,而且我想在我花了很长时间埋在探查器之前如果我错过了更快的方法来做到这一点在.NET框架内?
修改 取出双反转(这意味着我们不需要转换为char数组)给出了相当不错的性能,对于记录,我的实现看起来有点像:
private string GetCommonSuffix(string[] lines)
{
int lineCount = lines.GetLength(0);
string currentSuffix = lines[0];
int currentSuffixLength = currentSuffix.Length;
for (int i = 1; i < lineCount; i++)
{
string thisLine = lines[i];
if (!thisLine.EndsWith(currentSuffix))
{
int thisLineLength = thisLine.Length;
int maxPossible = thisLineLength < currentSuffixLength ? thisLineLength : currentSuffixLength;
if (maxPossible == 0)
{
return string.Empty;
}
for (int j = 1; j < maxPossible; j++)
{
if( currentSuffix[ currentSuffixLength - j ] != thisLine[ thisLineLength - j ] )
{
currentSuffix = currentSuffix.Substring(currentSuffixLength - j + 1, j - 1);
currentSuffixLength = j - 1;
break;
}
}
}
}
return currentSuffix;
}
答案 0 :(得分:3)
好吧,首先,您不需要将字符串转换为char数组。您可以在字符串中使用索引器来获取单个字符。
可能值得把它想象成数字而不是字符串...每个成对比较会给你一个最大值,最后的数字(后缀的大小)是最小的那些最大值。
所以有两种方法可以表明自己:
我个人可能会采用第一种方法 - 它不具备良好的缓存一致性,但我认为在某些情况下它会更好(例如许多字符串,除了其中一种之外都有很长的共同点后缀。
(当然,一旦你掌握了长度,获得实际的子串非常简单。)
答案 1 :(得分:1)
你的方法似乎没问题。你可以迭代所有的字符串,而不是一次只能两个,这样可以节省一些反转(如果最后一个字符串没有共同的前缀,但是所有其他字符串都做了很多时间 - 你需要做很多工作没有任何与明智的方法)
在完成所有比较之前,也无需撤消当前的候选公共后缀。
但是,您可以通过将索引数组保持在每个字符串的位置,将每个索引初始化为字符串的长度(减1)并从末尾向后工作,迭代所有字符串来避免反转。 / p>
答案 2 :(得分:0)
这可能是Memoized递归函数的一个很好的候选者,因为您可能希望保留先前计算的值。
基本示例:http://weblogs.asp.net/podwysocki/archive/2008/08/01/recursing-into-recursion-memoization.aspx
或: http://explodingcoder.com/blog/content/painless-caching-memoization-net
可能适合,可能没用:)