文字列で与えられたword
とString配列book
いくつかの文字列が含まれています。プログラムが作成する可能性の数を配る必要があるword
の要素を使用してのみbook
。私たちが望むよう要素は何回でも使用することができ、プログラムは6秒未満で終了しなければなりません。
例えば、入力:
String word = "stackoverflow";
String[] book = new String[9];
book[0] = "st";
book[1] = "ck";
book[2] = "CAG";
book[3] = "low";
book[4] = "TC";
book[5] = "rf";
book[6] = "ove";
book[7] = "a";
book[8] = "sta";
出力は次のようになります2
私たちが作成することができるので、"stackoverflow"
2通りの方法で:
1:"st"
+ "a"
+ "ck"
+ "ove"
+ "rf"
+"low"
2:"sta"
+ "ck"
+ "ove"
+ "rf"
+"low"
プログラムの私の実装では、場合にのみ、必要な時間で終了するword
比較的小さい(<15文字)です。私は前に述べたようにしかし、プログラムの実行中の制限時間は6秒であり、非常に大きな処理できる必要がありますword
文字列(> 1000文字)。ここで大入力の一例です。
ここに私のコードは次のとおりです。
1)実際の方法。
入力:文字列word
と文字列[]book
出力:方法ワードの数だけ本の中で文字列を使用して書き込むことができます
public static int optimal(String word, String[] book){
int count = 0;
List<List<String>> allCombinations = allSubstrings(word);
List<String> empty = new ArrayList<>();
List<String> wordList = Arrays.asList(book);
for (int i = 0; i < allCombinations.size(); i++) {
allCombinations.get(i).retainAll(wordList);
if (!sumUp(allCombinations.get(i), word)) {
allCombinations.remove(i);
allCombinations.add(i, empty);
}
else count++;
}
return count;
}
2)allSubstrings():
入力:文字列 input
出力:リストのリスト、各入力まで追加のサブストリングの組み合わせを含みます
static List<List<String>> allSubstrings(String input) {
if (input.length() == 1) return Collections.singletonList(Collections.singletonList(input));
List<List<String>> result = new ArrayList<>();
for (List<String> temp : allSubstrings(input.substring(1))) {
List<String> firstList = new ArrayList<>(temp);
firstList.set(0, input.charAt(0) + firstList.get(0));
if (input.startsWith(firstList.get(0), 0)) result.add(firstList);
List<String> l = new ArrayList<>(temp);
l.add(0, input.substring(0, 1));
if (input.startsWith(l.get(0), 0)) result.add(l);
}
return result;
}
3.)sumup():
入力:A文字列のリストinput
と文字列expected
出力:真の要素の場合input
まで追加expected
public static boolean sumUp (List<String> input, String expected) {
String x = "";
for (int i = 0; i < input.size(); i++) {
x = x + input.get(i);
}
if (expected.equals(x)) return true;
return false;
}
私は私が間違って何をやっていた考え出した私の前の回答を:私はメモ化を使用していなかった、私は不必要な作業の非常に多くをやり直したので。
本の配列を検討{"a", "aa", "aaa"}
し、ターゲットワードを"aaa"
。このターゲットを構築するための4つの方法があります。
"a" + "a" + "a"
"aa" + "a"
"a" + "aa"
"aaa"
私の以前の試みは別に、4つのすべての散歩を持っているでしょう。しかし、その代わりに、1はそれを観察することができます。
- 構築するための1つの方法があります
"a"
- あなたは構築できる
"aa"
2つの方法で、いずれか"a" + "a"
または使用して"aa"
直接。 - あなたは、構築することができます
"aaa"
使用するか"aaa"
、直接(1つの道を)。又は"aa" + "a"
(構築する2つの方法があるので、2ウェイ"aa"
)。または"a" + "aa"
(1ウェイ)。
ここで第三のステップは、唯一、我々はそれを構成することができるいくつかの方法を知っているため、以前に構築された文字列に単一の追加の文字列を追加することに注意してください。
このことは、私たちがのプレフィックス多くの方法数える場合word
に構築することができますが、我々は自明長いプレフィックスからわずか1以上の文字列を追加することによって、いくつかの方法を計算するためにそれを使用することができますがbook
。
あなたはすぐのプレフィックスルックアップすることができますので、私は、簡単なトライクラスを定義したbook
単語をその任意の位置での試合word
:
class TrieNode {
boolean word;
Map<Character, TrieNode> children = new HashMap<>();
void add(String s, int i) {
if (i == s.length()) {
word = true;
} else {
children.computeIfAbsent(s.charAt(i), k -> new TrieNode()).add(s, i + 1);
}
}
}
各文字のためにs
、これはのインスタンスを作成しTrieNode
、格納するTrieNode
後続文字の等
static long method(String word, String[] book) {
// Construct a trie from all the words in book.
TrieNode t = new TrieNode();
for (String b : book) {
t.add(b, 0);
}
// Construct an array to memoize the number of ways to construct
// prefixes of a given length: result[i] is the number of ways to
// construct a prefix of length i.
long[] result = new long[word.length() + 1];
// There is only 1 way to construct a prefix of length zero.
result[0] = 1;
for (int m = 0; m < word.length(); ++m) {
if (result[m] == 0) {
// If there are no ways to construct a prefix of this length,
// then just skip it.
continue;
}
// Walk the trie, taking the branch which matches the character
// of word at position (n + m).
TrieNode tt = t;
for (int n = 0; tt != null && n + m <= word.length(); ++n) {
if (tt.word) {
// We have reached the end of a word: we can reach a prefix
// of length (n + m) from a prefix of length (m).
// Increment the number of ways to reach (n+m) by the number
// of ways to reach (m).
// (Increment, because there may be other ways).
result[n + m] += result[m];
if (n + m == word.length()) {
break;
}
}
tt = tt.children.get(word.charAt(n + m));
}
}
// The number of ways to reach a prefix of length (word.length())
// is now stored in the last element of the array.
return result[word.length()];
}
以下のためにOPによって与えられた非常に長い入力、これは出力が得られます。
$ time java Ideone
2217093120
real 0m0.126s
user 0m0.146s
sys 0m0.036s
かなり速く必要な6秒以上 - これはあまりにもJVM起動時間を含んでいます。
編集:実際には、トライは必要ありません。あなたは、単にと「トライウォーク」ループを置き換えることができます。
for (String b : book) {
if (word.regionMatches(m, b, 0, b.length())) {
result[m + b.length()] += result[m];
}
}
そしてそれはまだ道速く6Sよりも遅く実行しますが、:
2217093120
real 0m0.173s
user 0m0.226s
sys 0m0.033s