前書き
私たちは、で議論している前の記事我々はconsistantly働い二つの配列を維持する必要があれば、私たちはより良い代わりに地図を使うべき最も一般的な状況で、。そして、それは地図が最初の場所で導入された理由です。しかし、アレイは、地図を得意とすることができますいくつかのケースもあります。
最初の質問は常に、なぜ我々は気にしていますか?我々はすでに地図を使って快適に感じます。その答えは、Arrayは地図よりも早く動作しますです。我々はスピードを改善したい場合は、いくつかの状況では、我々は、Arrayを使用してに戻ることができます。配列は高速ですが、常に我々はそれを使用することができません。それは我々が(A〜Z)英語のアルファベットで作業するとき、です。私たちはこれらの状況で地図を使用する場合は、もちろん、それは意志罰金に動作します。しかし、唯一の26英語の文字がある、のは考え直してみましょう。我々は、店舗地図の主要なセクションで、「」〜「Z」、それら以外の、配列のインデックスが0〜25として保存することができますか?はい、私たちは/指名0が手配することができ、1は2はc、bは、というように、代わりに本物の「」、「B」と「c」を格納します。この考え方の基本は、最終的には、我々は我々のアプリケーションは、よりefficently作品にするには、アレイを使用することができます。
のは、私たちは、上記のアイデアのより多くの意味を作る手助け、2つのLeetCodeの質問を見てみましょう。
LeetCode 1160
「文字を用いて形成することができる言葉を見つけます」
あなたは、文字列の配列を指定され words
、文字列を chars
。
文字列がある 良い 、それはから文字を用いて形成することができる場合 chars
(各文字は一度だけ使用することができます)。
内のすべての良い文字列の長さの合計を返します words
。
例1:
入力:言葉= [「猫」、「BT」、「帽子」、「木」]、文字= 「atach」
出力:6
説明:
答えはあるように形成することができる文字列は「猫」と「帽子」です3 + 3 = 6。
例2:
入力:言葉= [「こんにちは」、「世界」、「leetcode」]、文字= 「welldonehoneyr」
出力:10
説明:
答えは5 + 5 =であるように形成することができる文字列は、「こんにちは」と「世界」です10。
私たちは地図を使用している場合:
FUNC countCharacters(単語[]の文字列、文字列)INT { 長さ:= 0 _ために、単語:=範囲単語{ //各ループ内charAvailableリセット charAvailable:=メイク(地図[ストリング] INT) _ため、C:=範囲文字{ charAvailable [列(C)] ++ } 失敗:=偽 _ため、C:=レンジワード{ NUM、_:= charAvailable [列(C)] numは> 0 {もし charAvailable [列(C)] - }他{ =真のフェイル ブレークを } } 場合{失敗! 長さ+ = LEN(ワード) } } 戻り値の長さ }
このソリューションは、正しいです。速度が速い囲碁ユーザーのわずか5%よりも100ミリ秒程度であり、そのウェブサイトのショー。
私たちは、「charAvailable」地図をリセットする必要があり、各ループを見ることができ、それは非常に時間がかかります。
メイク()関数の引数の少しの助けを借りて、我々はcharAvailableにそれを変更することができます=メイク(マップ[文字列] int型、lenは(文字)/ 2)。この時間の缶ヘルプ低下20msのはconsumping、まだ最適化の余地があります。
私たちは、スピードを向上させるために二つのことの助けをしたいです:
1.私たちは、より高速な地図以外のデータ構造体を見つけることができますか?
2.私たちは、一度だけ「charAvailable」を初期化し、各ループのためにそれをコピーすることができますか?
まず、ここでのスライスは、アレイに裏打ちされています。その他のすべてのアイデアは、上記と全く同じです。
FUNCのcountCharacters(単語[]の文字列、文字列)INT { = 0:長さ =レンジワード{:_、単語の //各ループ内charAvailableリセット charAvailable:=メイク([] INT、26) _、Cのために:=範囲の文字は{ charAvailable [C-'A '] ++ } 失敗:= FALSE =レンジワード{:_、C用の 場合charAvailable [C-'A']> 0 { charAvailable [C-'A '] - }他の{ 失敗=真の ブレーク } } もし!失敗{ 長さ+ = LEN(ワード) } } 戻り長さ }
速度が速い囲碁ユーザーの100%よりも10ミリ秒程度であり、そのウェブサイトのショー。それは十分に良いです。
我々はさらに行けば、我々はリーチループに代わりにリセットを、一度だけ「charAvailable」を初期化したいです。
だから、第二に、我々は機能と呼ばれるコピーでビルドを知るようになるだろう()。私たちは、「=」を使用している場合、この機能ではなく、ポインタのコピーを、2つのスライスの間の値のコピーを作成することができます。
この関数は、もう少し明確に我々のコードを作ることができます。我々は、ループの前に、一度だけ「charAvailable」を初期化します。ウェブサイトは、このプロセスの速度は10msの周りにもあることを示しています。
FUNC countCharacters(単語[]の文字列、文字列)INT { 長さ:= 0 charAvailable:=メイク([] INT、26) _、Cのために:=範囲文字{ charAvailable [C-'A '] ++ } ため_ 、単語:=レンジワード{ charAv:=メイク([] INT、26) コピー(charAv、charAvailable) 失敗:=偽 _ため、C:=レンジワード{ charAv [C-'A ']なら> 0 { charAv [C-'A '] - }他{ 失敗=真 ブレーク } } の場合に失敗{! 長さ+ = LEN(ワード) } } 戻り長さ }
我々は配列を使用するように、それはほとんど同じです。我々はすでに「=」二つの配列の間には、デフォルトで値のコピーを行います知っていました。ウェブサイトのショー速度も10msのまわりにあります。
FUNC countCharacters(単語[]の文字列、文字列)INT { 長さ:= 0 charAvailable:= [26] INT {} _、Cのために:=範囲文字{ charAvailable [C-'A '] ++ } _、単語のための:=レンジワードは{ charAv:= charAvailable 失敗:=偽 _ために、C:=レンジワード{ '0 {> charAv [C-'A]場合 charAv [C-'A]' - {他} 失敗=真 ブレーク } } もし!失敗{ 長さ+ = LEN(ワード) } } 戻り値の長さ }