私が Big O 記法を理解していて、この時点での私の理解がおそらくほとんどのものよりもはるかに低いと信じている場合、Keyser のコメントによると、次のコード行はO(n 2 )であり、これは実際にはすでにO(n)操作です。
"Hello, World!".ToLower().Contains("a");
ToLower()
操作であり、O(n)
操作でもあるためですContains
。多分それO(n + n)
は、繰り返しますが、私の理解はまだ曖昧です。
注:Release
以下は、ビルドで実行されたテスト メソッドのリストであり、Stopwatch
クラスを利用して実行時間を追跡します。
しかし、もっと速くしたいので、次の 3 つのテスト方法を検討してください。
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
理想的には、文字列全体をスキャンする必要はありません。さらに、2 番目の全体的なテストでTestHashSet
ある は、HashSet
.
振り返ってみると、最後の 2 つの方法が遅い理由がわかると思います。最初のアルゴリズムと同じアルゴリズムを使用しているため (つまり、文字列全体を少なくとも 2 回処理する必要があるため)、速度が遅いと思いますが、その上で、その後にルックアップを行っています。
このアルゴリズムを高速化するにはどうすればよいですか? 大文字と小文字を区別せずに文字列を比較する必要がある場合に、これをよく使用します。