Let N be the length of the given string and R the number of rules.
Extending the tree from top to bottom gives the computational complexity O (NR ^ N) in the worst case (an input line of type aaa... and rules aa -> a ).
Evidence:
The root of the tree has (N-1) R children who have (N-1) R ^ 2 children, ... who have (N-1) R ^ N children (leaves). Thus, the total complexity is O ((N-1) R + (N-1) R ^ 2 + ... (N-1) R ^ N) = O (N (1 + R 2 + ... + R ^ N)) = (using the binomial theorem ) = O (N (R + 1) ^ N) = O (NR ^ N).
Recursive Java implementation of this naive approach:
public static void main(String[] args) { Map<String, Character[]> rules = new HashMap<String, Character[]>() {{ put("ab", new Character[]{'b', 'c'}); put("ba", new Character[]{'a'}); put("cc", new Character[]{'b'}); }}; System.out.println(simplify("abab", rules)); } public static Set<String> simplify(String in, Map<String, Character[]> rules) { Set<String> result = new HashSet<String>(); simplify(in, rules, result); return result; } private static void simplify(String in, Map<String, Character[]> rules, Set<String> result) { if (in.length() == 1) { result.add(in); } for (int i = 0; i < in.length() - 1; i++) { String two = in.substring(i, i + 2); Character[] rep = rules.get(two); if (rep != null) { for (Character c : rep) { simplify(in.substring(0, i) + c + in.substring(i + 2, in.length()), rules, result); } } } }
Original version of Bas Swinckels O (RN ^ 3) Java (with HashMap as memoization cache):
public static Set<String> simplify2(final String in, Map<String, Character[]> rules) { Map<String, Set<String>> cache = new HashMap<String, Set<String>>(); return simplify2(in, rules, cache); } private static Set<String> simplify2(final String in, Map<String, Character[]> rules, Map<String, Set<String>> cache) { final Set<String> cached = cache.get(in); if (cached != null) { return cached; } Set<String> ret = new HashSet<String>(); if (in.length() == 1) { ret.add(in); return ret; } for (int i = 1; i < in.length(); i++) { String head = in.substring(0, i); String tail = in.substring(i, in.length()); for (String c1 : simplify2(head, rules)) { for (String c2 : simplify2(tail, rules, cache)) { Character[] rep = rules.get(c1 + c2); if (rep != null) { for (Character c : rep) { ret.add(c.toString()); } } } } } cache.put(in, ret); return ret; }
The conclusion in both approaches:
[b, c]