你能加速这个算法吗? C#/ C ++

时间:2016-02-14 15:06:39

标签: c# c++ string algorithm

嘿,我一直在做一些事情,现在变得相对较大(而且很慢)。然而,在关闭了时间函数测量后,我设法找出了瓶颈。

说我想“置换”字符串“ABC”。我所说的“permute”并不是一种排列,而是一种遵循这种模式的连续子串集:

A
AB
ABC

B
BC

C

如果它包含在另一个字符串S2中,我必须检查每个子字符串,所以我做了一些quick'n脏文字实现,如下所示:

for (int i = 0; i <= strlen1; i++)
{
   for (int j = 0; j <= strlen2- i; j++)
   {
      sub = str1.Substring(i, j);
      if (str2.Contains(sub)) {do stuff}
      else break;

这最初很慢但是一旦我意识到如果第一部分不存在,就没有必要检查后续的那些意味着如果sub不包含在str2中,我可以在内部循环上调用break。

好的,这给了超快的结果但计算我的算法复杂度我意识到在最坏的情况下这将是N ^ 4?我忘了str.contains()和str.substr()都有自己的复杂性(N或N ^ 2我忘记了)。

我在第二个for循环中有大量调用的事实使它表现得相当好...... N ^ 4~足够说了。

然而,我在数学上使用概率论来计算平均运行时间来评估随机生成的字符串池中的子串的增长概率(这是我的基线),测量概率何时变为> 1。 0.5(50%)

这显示了不同字符数和字符串长度(粗略)之间的指数关系,这意味着在我使用算法的场景中,string1的长度(最可能)永远不会超过7

因此,平均复杂度为~O(N * M),其中N是字符串长度1,M是字符串长度2.由于我在常数M的函数中测试了N,我得到了线性增长~O(N)(与N ^ 4 eh相反不错?)

我做了时间测试并绘制了一个显示近乎完美的线性增长的图表,所以我得到了与我的数学预测匹配的实际结果(耶!)

然而,这并没有考虑到string.contains()和string.substring()的成本,这让我想知道这是否可以进一步优化?

我一直在考虑用C ++制作这个,因为我需要相当低级的东西?你们有什么感想?我已经花了很多时间分析这个希望,我已经详细阐述了一切:)!

2 个答案:

答案 0 :(得分:1)

您的问题被标记为C ++和C#。

在C ++中,最佳解决方案是使用迭代器和std::search。原始字符串保持不变,并且不会创建任何中间对象。根本不会发生你的Substring()的等价物,所以这消除了这部分开销。

这应该达到理论上最佳的性能:强力搜索,测试所有排列,没有中间对象构造或破坏,除了迭代器本身,它只是替换你的两个int索引变量。我无法想到任何更快的方法来实现这个基本算法。

答案 1 :(得分:1)

您是否针对一个字符串测试一个字符串?如果你对另一串字符串测试一堆字符串,那就完全不同了。即使你有一个最好的算法来比较一个字符串和另一个O(X),它并不意味着重复它M * N次你会得到最好的算法来处理M字符串对N.

当我做了一些类似的东西时,我构建了所有N个字符串的所有子串的字典

Dictionary<string, List<int>>

string是子字符串,int是包含该子字符串的字符串的索引。然后我测试了所有M个字符串的所有子串。速度突然不是O(M*N*X),而是O(max(M,N)*S),其中S是一个字符串的子串数。取决于可能更快的M,N,X,S。我不是说子串的字典是最好的方法,我只想指出你应该总是试着看到整个画面。