これは宿題ではないと思います。(もしそうなら、あなたはあなた自身の盗作です!;-)
以下は、手っ取り早い解決策です。時間計算量は次のとおりですO(m**2 * n)
。ここm
で、は平均文字列長であり、n
は文字列配列のサイズです。
のインスタンスはOccurrence
、指定された文字列を含むインデックスのセットを保持します。commonOccurrences
ルーチンは文字列配列をスキャンし、null以外の各文字列を呼び出しますcaptureOccurrences
。captureOccurrences
ルーチンは、現在のインデックスを、指定されOccurrence
た文字列の可能なサブ文字列ごとに配置します。最後に、少なくとも2つのインデックスを持つcommonOccurrences
ものだけを選択して、結果セットを作成します。Occurrences
サンプルデータには、質問で特定したよりも多くの一般的なサブストリングが含まれていることに注意してください。たとえば"00ab"
、各入力文字列で発生します。コンテンツ(たとえば、すべての数字、すべてのアルファベットなど)に基づいて興味深い文字列を選択するための追加のフィルターは、読者の練習問題として残されています。;-)
迅速で汚いJavaソース:
package com.stackoverflow.answers;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
public class CommonSubstringFinder {
public static final int MINIMUM_SUBSTRING_LENGTH = 2;
public static class Occurrence implements Comparable<Occurrence> {
private final String value;
private final Set<Integer> indices;
public Occurrence(String value) {
this.value = value == null ? "" : value;
indices = new TreeSet<Integer>();
}
public String getValue() {
return value;
}
public Set<Integer> getIndices() {
return Collections.unmodifiableSet(indices);
}
public void occur(int index) {
indices.add(index);
}
public String toString() {
StringBuilder result = new StringBuilder();
result.append('"').append(value).append('"');
String separator = ": ";
for (Integer i : indices) {
result.append(separator).append(i);
separator = ",";
}
return result.toString();
}
public int compareTo(Occurrence that) {
return this.value.compareTo(that.value);
}
}
public static Set<Occurrence> commonOccurrences(String[] strings) {
Map<String,Occurrence> work = new HashMap<String,Occurrence>();
if (strings != null) {
int index = 0;
for (String string : strings) {
if (string != null) {
captureOccurrences(index, work, string);
}
++index;
}
}
Set<Occurrence> result = new TreeSet<Occurrence>();
for (Occurrence occurrence : work.values()) {
if (occurrence.indices.size() > 1) {
result.add(occurrence);
}
}
return result;
}
private static void captureOccurrences(int index, Map<String,Occurrence> work, String string) {
final int maxLength = string.length();
for (int i = 0; i < maxLength; ++i) {
for (int j = i + MINIMUM_SUBSTRING_LENGTH; j < maxLength; ++j) {
String partial = string.substring(i, j);
Occurrence current = work.get(partial);
if (current == null) {
current = new Occurrence(partial);
work.put(partial, current);
}
current.occur(index);
}
}
}
private static final String[] TEST_DATA = {
"0000abcde0000",
"0000abcd00000",
"000abc0000000",
"00abc000de000",
};
public static void main(String[] args) {
Set<Occurrence> found = commonOccurrences(TEST_DATA);
for (Occurrence occurrence : found) {
System.out.println(occurrence);
}
}
}
サンプル出力:(実際には1行に1回しか発生しなかったことに注意してください。ブロッククォートのマークアップが行をマージするのを防ぐことはできないようです)
"00":0,1,2,3 "000":0,1,2,3
"0000":0,1,2 "0000a":0,1
"0000ab":0,1 "0000abc":0 、1
"0000abcd":0,1 "000a":0,1,2
"000ab":0,1,2 "000abc":0,1,2
"000abcd":0,1 "00a":0,1 、2,3
"00ab":0,1,2,3 "00abc":0,1,2,3
"00abc0":2,3 "00abc00":2,3
"00abc000":2,3 "00abcd" :0,1
"0a":0,1,2,3 "0ab":0,1,2,3
"0abc":0,1,2,3 "0abc0":2,3
"0abc00":2 3 "0abc000":2,3
"0abcd":0,1 "ab":0,1,2,3 "abc":0,1,2、3 "abc0":2,3 "abc00":2,3
"abc000":2,3 "abcd":0,1 "bc":0,1,2,3 "bc0":2,3 "bc00" :2,3
"bc000":2,3 "bcd":0,1 "c0":2,3 "c00":2,3 "c000":2,3 "cd":0,1
"de":0,3 "de0":0,3 "de00":0,3
"e0":0,3 "e00":0,3