1 回答
TA贡献1828条经验 获得超3个赞
问题来源
在经历了持续两天三夜的光荣战斗(以及来自评论的惊人想法和想法)之后,我终于设法解决了这个问题!
我想为遇到类似问题的任何人发布一个答案,其中该string.Substring(i, j)函数不是获取字符串子字符串的可接受解决方案,因为字符串太大并且您无法负担string.Substring(i, j)(它必须制作一个副本,因为 C# 字符串是不可变的,无法绕过它)或者在string.Substring(i, j)同一个字符串上被大量调用(就像在我的嵌套 for 循环中)给垃圾收集器带来了困难,或者就像我的情况一样!
尝试
我已经尝试了许多建议的东西,例如StringBuilder、Streams、在块内使用Intptr和Marshal 的非托管内存分配unsafe{},甚至创建一个 IEnumerable 并通过引用返回给定位置内的字符。所有这些尝试最终都失败了,因为必须完成某种形式的数据连接,因为我没有简单的方法可以在不影响性能的情况下逐个字符地遍历我的树。如果只有一种方法可以一次跨越数组中的多个内存地址,就像您可以在 C++ 中使用一些指针算法一样......除了有......(归功于@Ivan Stoev 的评论)
解决方案
解决方案是使用System.ReadOnlySpan<T>(不可能是System.Span<T>因为字符串是不可变的),除其他外,它允许我们在不创建副本的情况下读取现有数组中内存地址的子数组。
这段代码发布:
string _s1 = s1.Substring(i, j);
if (stree.has(_s1))
{
score += j - i;
longest = j - i;
}
更改为以下内容:
if (stree.has(i, j))
{
score += j - i;
longest = j - i;
}
哪里stree.has()现在需要两个整数(子字符串的位置和长度)并执行:
ReadOnlySpan<char> substr = s1.AsSpan(i, j);
请注意,substr变量实际上是对初始s1数组字符子集的引用,而不是副本!(该s1变量已可从此函数访问)
请注意,在撰写本文时,我使用的是 C#7.2 和 .NET Framework 4.6.1,这意味着要获得 Span 功能,我必须转到 Project > Manage NuGet Packages,勾选“Include prerelease”复选框并浏览 System .内存并安装它。
重新运行初始测试(在长度为 100 万个字符的字符串上,即 1MB)速度从 2+ 分钟(我在 2 分钟后放弃等待)增加到 ~86 毫秒!!
- 1 回答
- 0 关注
- 208 浏览
添加回答
举报