好的,我甚至成功创建了NFA,然后将其转换为DFA,并构建所有DFA的交集,同时使用BFS访问它们。对于前三个测试代码样本,它运行得很快,但是最后两个似乎对算法处理过于复杂。如果我使用A*,我可以得到一些解决方案,但问题在于它不是最短的!
import java.util.*;
import java.util.stream.Collectors;
public class Safe4 {
public static void main(String[] args) {
String[] patterns = new String[3];
patterns[0] = "?a*b";
patterns[1] = "a*b*";
patterns[2] = "*a??a*";
System.out.println(new Safe4().solution(patterns));
patterns = new String[3];
patterns[0] = "*p?qp?*bd*pd?q*";
patterns[1] = "*qp*d?b*?p?d*";
patterns[2] = "?*d?b???q*q?p*";
System.out.println(new Safe4().solution(patterns));
patterns = new String[2];
patterns[0] = "*z*y*y*z*x*x*x*z*x*z*y*z*y*x*x*y*y*y*z*x*y*z*y*x*x*x*z*x*z*z*z*y*y*z*x*y*z*";
patterns[1] = "*y*z*z*x*x*y*z*y*z*y*x*z*y*z*y*x*z*y*x*y*x*y*y*z*x*y*z*x*x*z*y*z*y*y*x*z*y*";
System.out.println(new Safe4().solution(patterns));
patterns = new String[5];
patterns[0] = "*i*o*?*?*u?*??*e?o*e*a*a*i*ee*";
patterns[1] = "*e*?ue*o*i*?*e*u*i*?*oa?*??*";
patterns[2] = "*?oi*i??uu*a*iu*?*?a*u*ia*u*";
patterns[3] = "*o*e*ea?*eu*?e?*ea*u*u?u*iu*";
patterns[4] = "*u*?oe*u*e?*e??ou?*oa*?*i*?a?*";
System.out.println(new Safe4().solution(patterns));
patterns = new String[95];
patterns[0] = "??????????????????????????";
patterns[1] = "*a*n*";
patterns[2] = "*i*x*";
patterns[3] = "*q*v*";
patterns[4] = "*u*l*";
patterns[5] = "*p*n*";
patterns[6] = "*j*c*";
patterns[7] = "*j*h*";
patterns[8] = "*q*h*";
patterns[9] = "*p*w*";
patterns[10] = "*p*v*";
patterns[11] = "*r*s*";
patterns[12] = "*j*x*";
patterns[13] = "*i*j*";
patterns[14] = "*t*h*";
patterns[15] = "*u*x*";
patterns[16] = "*i*l*";
patterns[17] = "*k*s*";
patterns[18] = "*u*j*";
patterns[19] = "*p*o*";
patterns[20] = "*p*r*";
patterns[21] = "*a*z*";
patterns[22] = "*t*f*";
patterns[23] = "*b*c*";
patterns[24] = "*e*g*";
patterns[25] = "*l*z*";
patterns[26] = "*d*c*";
patterns[27] = "*u*g*";
patterns[28] = "*l*g*";
patterns[29] = "*r*z*";
patterns[30] = "*y*b*";
patterns[31] = "*g*c*";
patterns[32] = "*t*h*";
patterns[33] = "*w*f*";
patterns[34] = "*i*e*";
patterns[35] = "*d*g*";
patterns[36] = "*r*m*";
patterns[37] = "*e*y*";
patterns[38] = "*q*n*";
patterns[39] = "*p*n*";
patterns[40] = "*y*a*";
patterns[41] = "*q*n*";
patterns[42] = "*l*j*";
patterns[43] = "*n*v*";
patterns[44] = "*p*b*";
patterns[45] = "*h*m*";
patterns[46] = "*r*b*";
patterns[47] = "*p*i*";
patterns[48] = "*u*b*";
patterns[49] = "*e*z*";
patterns[50] = "*d*b*";
patterns[51] = "*p*a*";
patterns[52] = "*s*d*";
patterns[53] = "*d*z*";
patterns[54] = "*k*x*";
patterns[55] = "*o*f*";
patterns[56] = "*s*g*";
patterns[57] = "*o*l*";
patterns[58] = "*t*g*";
patterns[59] = "*p*v*";
patterns[60] = "*j*z*";
patterns[61] = "*y*n*";
patterns[62] = "*o*b*";
patterns[63] = "*k*g*";
patterns[64] = "*i*d*";
patterns[65] = "*c*v*";
patterns[66] = "*q*m*";
patterns[67] = "*e*k*";
patterns[68] = "*w*j*";
patterns[69] = "*i*f*";
patterns[70] = "*i*t*";
patterns[71] = "*i*b*";
patterns[72] = "*i*k*";
patterns[73] = "*p*w*";
patterns[74] = "*a*x*";
patterns[75] = "*p*z*";
patterns[76] = "*r*v*";
patterns[77] = "*y*c*";
patterns[78] = "*i*b*";
patterns[79] = "*n*v*";
patterns[80] = "*g*v*";
patterns[81] = "*u*k*";
patterns[82] = "*w*i*";
patterns[83] = "*e*f*";
patterns[84] = "*l*s*";
patterns[85] = "*t*v*";
patterns[86] = "*y*d*";
patterns[87] = "*p*e*";
patterns[88] = "*h*b*";
patterns[89] = "*s*f*";
patterns[90] = "*o*x*";
patterns[91] = "*i*z*";
patterns[92] = "*q*e*";
patterns[93] = "*r*c*";
patterns[94] = "*k*h*";
System.out.println(new Safe4().solution(patterns));
}
class NFA {
Map<Integer, Map<Character, Set<Integer>>> table;
int initState;
int lastState;
public NFA(Map<Integer, Map<Character, Set<Integer>>> table, int initState, int lastState) {
this.table = table;
this.initState = initState;
this.lastState = lastState;
}
}
private NFA createNFA(Set<Character> chars, String p) {
int state = 0;
boolean wasStar = false;
Map<Integer, Map<Character, Set<Integer>>> nfa = new HashMap<>();
for (char c : p.toCharArray()) {
if (c == '*') {
Map<Character, Set<Integer>> m1 = nfa.computeIfAbsent(state, k -> new HashMap<>());
for (char c1 : chars) {
m1.computeIfAbsent(c1, k -> new TreeSet<>()).add(state);
}
m1.computeIfAbsent('X', k -> new TreeSet<>()).add(state);
wasStar = true;
state--;
} else if (c == '?') {
if (wasStar) {
Map<Character, Set<Integer>> m1 = nfa.get(state);
for (char c1 : chars) {
m1.computeIfAbsent(c1, k -> new TreeSet<>()).add(state);
}
m1.computeIfAbsent('X', k -> new TreeSet<>()).add(state);
}
Map<Character, Set<Integer>> m1 = nfa.computeIfAbsent(state, k -> new HashMap<>());
for (char c1 : chars) {
m1.computeIfAbsent(c1, k -> new TreeSet<>()).add(state + 1);
}
m1.computeIfAbsent('X', k -> new TreeSet<>()).add(state + 1);
wasStar = false;
} else {
if (wasStar) {
nfa.get(state).get(c).add(state);
}
Map<Character, Set<Integer>> m1 = nfa.computeIfAbsent(state, k -> new HashMap<>());
m1.computeIfAbsent(c, k -> new TreeSet<>()).add(state + 1);
wasStar = false;
}
state++;
}
return new NFA(nfa, 0, state);
}
class DFA {
Map<Integer, Map<Character, Integer>> table;
int initState;
Set<Integer> lastStates;
public DFA(Map<Integer, Map<Character, Integer>> table, int initState, Set<Integer> lastStates) {
this.table = table;
this.initState = initState;
this.lastStates = lastStates;
}
}
private DFA convertToDFA(Set<Character> chars, NFA nfa) {
Set<Character> charsWithX = new TreeSet<>(chars);
charsWithX.add('X');
Map<Integer, Map<Character, Integer>> dfa = new HashMap<>();
Queue<Integer> sq = new LinkedList<>();
int newUsableState = nfa.lastState + 1;
Set<Integer> lastStates = new TreeSet<>();
Map<Integer, Set<Integer>> newStateToStates = new HashMap<>();
Map<Set<Integer>, Integer> statesToNewState = new HashMap<>();
sq.offer(0);
Integer currS;
while ((currS = sq.poll()) != null) {
Map<Character, Integer> m1 = dfa.computeIfAbsent(currS, k -> new HashMap<>());
if (currS <= nfa.lastState) {
if (nfa.table.get(currS) != null) {
for (Map.Entry<Character, Set<Integer>> charToStates : nfa.table.get(currS).entrySet()) {
Integer newState;
if (charToStates.getValue().size() == 1) {
newState = charToStates.getValue().stream().findAny().get();
if (newState == nfa.lastState) {
lastStates.add(newState);
}
} else {
newState = newUsableState++;
newStateToStates.putIfAbsent(newState, charToStates.getValue());
statesToNewState.putIfAbsent(charToStates.getValue(), newState);
if (charToStates.getValue().contains(nfa.lastState)) {
lastStates.add(newState);
}
}
m1.putIfAbsent(charToStates.getKey(), newState);
if (!dfa.containsKey(newState) && !sq.contains(newState)) {
sq.offer(newState);
}
}
} else {
}
} else {
Set<Integer> li = newStateToStates.get(currS);
for (Character c : charsWithX) {
Set<Integer> states = new TreeSet<>();
for (Integer i : li) {
Map<Character, Set<Integer>> maybeFinal = nfa.table.get(i);
if (maybeFinal != null) {
Set<Integer> exisStat = maybeFinal.get(c);
if (exisStat != null) {
states.addAll(exisStat);
}
}
}
if (!states.isEmpty()) {
Integer newState;
if (states.size() == 1) {
newState = states.stream().findAny().get();
if (newState == nfa.lastState) {
lastStates.add(newState);
}
} else {
newState = statesToNewState.get(states);
if (newState == null) {
newState = newUsableState++;
newStateToStates.putIfAbsent(newState, states);
statesToNewState.putIfAbsent(states, newState);
if (states.contains(nfa.lastState)) {
lastStates.add(newState);
}
}
}
m1.putIfAbsent(c, newState);
if (!dfa.containsKey(newState) && !sq.contains(newState)) {
sq.offer(newState);
}
}
}
}
}
return new DFA(dfa, 0, lastStates);
}
private Set<Character> chars(String p) {
Set<Character> chars = new TreeSet<>();
for (char c : p.toCharArray()) {
if (c > 96 && c < 123) {
chars.add(c);
}
}
return chars;
}
class RecNodeMulti {
final List<Integer> newState;
final char rec;
final RecNodeMulti parent;
public RecNodeMulti(List<Integer> newState, char rec, RecNodeMulti parent) {
this.newState = newState;
this.rec = rec;
this.parent = parent;
}
public String toRoot() {
StringBuilder sb = new StringBuilder();
RecNodeMulti rn = this;
while (rn.rec != Character.MIN_VALUE) {
sb.append(rn.rec);
rn = rn.parent;
}
return sb.reverse().toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RecNodeMulti that = (RecNodeMulti) o;
return rec == that.rec &&
Objects.equals(newState, that.newState);
}
@Override
public int hashCode() {
return Objects.hash(newState, rec);
}
}
RecNodeMulti root;
private String multiIntersectDFAWithBFS(Set<Character> charsSvi, List<DFA> dfaS) {
Set<Character> charsSviWithX = new TreeSet<>(charsSvi);
Set<RecNodeMulti> visited = new HashSet<>();
Queue<RecNodeMulti> sq = new LinkedList<>();
root = new RecNodeMulti(dfaS.stream().map(x -> x.initState).collect(Collectors.toList()), Character.MIN_VALUE, null);
sq.offer(root);
RecNodeMulti currS;
Map<List<Integer>, Integer> statesToNewState = new HashMap<>();
int newUsableState = dfaS.stream().mapToInt(x -> x.table.keySet().stream().mapToInt(y -> y).max().getAsInt()).max().getAsInt() + 1;
while ((currS = sq.poll()) != null) {
List<Map<Character, Integer>> statemap = new ArrayList<>();
for (int i = 0; i < dfaS.size(); i++) {
statemap.add(dfaS.get(i).table.get(currS.newState.get(i)));
}
for (char c1 : charsSviWithX) {
List<Integer> sIns = statemap.stream().map(x -> {
Integer in = x.get(c1);
if (in == null) {
return x.get('X');
}
return in;
}).collect(Collectors.toList());
if (sIns.stream().allMatch(Objects::nonNull)) {
Integer exisP = statesToNewState.get(sIns);
if (exisP == null) {
exisP = newUsableState++;
statesToNewState.put(sIns, exisP);
boolean allLast = true;
for (int i = 0; i < dfaS.size(); i++) {
if (!dfaS.get(i).lastStates.contains(sIns.get(i))) {
allLast = false;
break;
}
}
if (allLast) {
return currS.toRoot() + c1;
}
} else {
continue;
}
RecNodeMulti rnm = new RecNodeMulti(sIns, c1, currS);
if (!sq.contains(rnm) && !visited.contains(rnm)) {
visited.add(rnm);
sq.offer(rnm);
}
}
}
}
return null;
}
private String solution(String[] patterns) {
List<DFA> dfaS = new ArrayList<>();
Set<Character> charsSvi = new TreeSet<>();
for (String p : patterns) {
Set<Character> chars = chars(p);
charsSvi.addAll(chars);
NFA nfa = createNFA(chars, p);
DFA dfa = convertToDFA(chars, nfa);
dfaS.add(dfa);
}
return multiIntersectDFAWithBFS(charsSvi, dfaS);
}
}
*
表示0或多个任意字母” - 这有点含糊不清 - 它必须是0或多个相同的字母吗? - kaya3