何千ものファイルが次のように整理されているとします。最初にファイル名で並べ替え (大文字と小文字が区別されるため、大文字のファイルが小文字のファイルよりも前になります)、次にファイルを最初のファイルの名前と最初のファイルの名前を含むフォルダーにグループ化します。そのフォルダの最後のファイル。たとえば、フォルダは次のようになります。
Abel -> Cain
Camel -> Sloth
Stork -> basket
basking -> sleuth
tiger -> zebra
次に、大文字と小文字を区別しない検索文字列を指定s
して、一致するファイルを格納できるフォルダーを決定しますs
。フォルダの中を見ることはできませんし、見る必要もありません。ファイルが実際に存在する必要はありません。
いくつかの例:
("Abel", "Cain") matches s = "blue", since it contains "Blue"
("Stork", "basket") matches s = "arctic", since it contains "arctic"
("FA", "Fb") matches s = "foo", since it contains "FOo"
("Fa", "Fb") does NOT match s = "foo"
正式には: 閉じた範囲[a,b]
と小文字の stringが与えられた場合、その中に文字列がs
あるかどうかを判断します。c
[a,b]
lower(c) = s
私の最初の直感は、範囲の境界に対して大文字と小文字を区別しない検索を行うことでした。しかし、これが正しくないことは、最後の例から簡単にわかります。
強引な解決策は、すべての潜在的なファイル名を生成することです。たとえば、入力文字列"abc"
は候補を生成し"ABC", "ABc", "AbC", "Abc", "aBC", "aBc", "abC", "abc"
ます。次に、境界に対してそれぞれをテストします。このブルート フォース ソリューションの例を以下に示します。これはO(2^n)
だけど。
私の質問は、高速で正しいアルゴリズムがあるかどうかです。
Clojure でのブルート フォース ソリューション:
(defn range-contains
[first last string]
(and (<= (compare first string) 0)
(>= (compare last string) 0)))
(defn generate-cases
"Generates all lowercase/uppercase combinations of a word"
[string]
(if (empty? string)
[nil]
(for [head [(java.lang.Character/toUpperCase (first string))
(java.lang.Character/toLowerCase (first string))]
tail (generate-cases (rest string))]
(cons head tail))))
(defn range-contains-insensitive
[first last string]
(let [f (fn [acc candidate] (or acc (range-contains first last (apply str candidate))))]
(reduce f false (generate-cases string))))
(fact "Range overlapping case insensitive"
(range-contains-insensitive "A" "Z" "g") => true
(range-contains-insensitive "FA" "Fa" "foo") => true
(range-contains-insensitive "b" "z" "a") => false
(range-contains-insensitive "B" "z" "a") => true)