如果我理解大 O 表示法,并且相信我此时的理解可能远低于大多数人,那么根据 Keyser 的评论,以下代码行是O(n 2 ),这实际上已经是O(n)操作:
"Hello, World!".ToLower().Contains("a");
因为ToLower()
是一个O(n)
操作,Contains
也是。也许是O(n + n)
,再说一次,我的理解仍然模糊。
注意:下面是在Release
构建中运行的测试方法列表,并利用Stopwatch
该类来跟踪运行时间。
但是,我想让它更快,所以考虑这三种测试方法:
private static void TestToLower(int i)
{
var s = "".PadRight(i, 'A');
var sw = Stopwatch.StartNew();
s.ToLower().Contains('b');
sw.Stop();
_tests.Add(string.Format("ToLower{0}", i), sw.ElapsedMilliseconds);
}
private static void TestHashSet(int i)
{
var s = "".PadRight(i, 'A');
var sw = Stopwatch.StartNew();
var lookup = new HashSet<char>(s.ToLower().AsEnumerable());
lookup.Contains('b');
sw.Stop();
_tests.Add(string.Format("ToHashSet{0}", i), sw.ElapsedMilliseconds);
}
private static void TestHashSet2(int i)
{
var s = "".PadRight(i, 'A');
var sw = Stopwatch.StartNew();
var lookup = new HashSet<char>(s.ToLower().ToArray());
lookup.Contains('b');
sw.Stop();
_tests.Add(string.Format("ToHashSet2{0}", i), sw.ElapsedMilliseconds);
}
现在考虑执行这样的操作:
TestToLower(1000000);
TestToLower(2000000);
TestToLower(4000000);
TestHashSet(1000000);
TestHashSet(2000000);
TestHashSet(4000000);
TestHashSet2(1000000);
TestHashSet2(2000000);
TestHashSet2(4000000);
结果如下:
ToLower1000000: 22.00 ms
ToLower2000000: 40.00 ms
ToLower4000000: 84.00 ms
ToHashSet1000000: 48.00 ms
ToHashSet2000000: 73.00 ms
ToHashSet4000000: 145.00 ms
ToHashSet21000000: 58.00 ms
ToHashSet22000000: 107.00 ms
ToHashSet24000000: 219.00 ms
他们每个人显然仍然必须使用该ToLower
方法,但我正在尝试使用该方法HashSet
来加快查找速度。理想情况下,您不必扫描整个字符串。此外,我真的认为第二个整体测试TestHashSet
会更快,因为它不必创建大量内存来分配HashSet
.
回想起来,我认为为什么最后两种方法较慢。我相信它们更慢,因为我有与第一个相同的算法(即我必须至少遍历整个字符串两次),但除此之外,我还在进行查找。
我怎样才能使这个算法更快?我们经常使用它,无论大小写如何,我们都必须比较字符串。