- Decide the key that represents the information needed later.
- Update its count or stored state while scanning the input.
- Use constant-time expected lookups to detect matches or assemble the result.
Code notes
- 141 lines of Java from the credited upstream file 3435.java.
- The implementation visibly relies on sequence storage, hash lookup, ordered lookup.
- 16 loop blocks detected.
Complexity
Expected hash operations are constant time, but the surrounding scan and the number of stored keys determine total work and memory.
Check the problem constraints before deciding whether this complexity will pass.
Use this to learn the idea, then write your own version.
1enum State { INIT, VISITING, VISITED }2 3class Solution {4 public List<List<Integer>> supersequences(String[] words) {5 List<List<Integer>> ans = new ArrayList<>();6 List<int[]> edges = getEdges(words);7 List<Integer> nodes = getNodes(edges);8 int[] letterToIndex = getLetterToIndex(nodes);9 List<Integer>[] graph = new List[nodes.size()];10 11 for (int i = 0; i < nodes.size(); i++)12 graph[i] = new ArrayList<>();13 14 for (int[] edge : edges) {15 final int u = edge[0];16 final int v = edge[1];17 graph[letterToIndex[u]].add(letterToIndex[v]);18 }19 20 for (List<Integer> doubledSubset : getMinimumSubsets(graph)) {21 int[] freq = new int[26];22 for (final int letter : nodes)23 freq[letter] = 1;24 for (final int index : doubledSubset)25 freq[nodes.get(index)] = 2;26 ans.add(Arrays.stream(freq).boxed().collect(Collectors.toList()));27 }28 29 return ans;30 }31 32 33 34 private List<List<Integer>> getMinimumSubsets(List<Integer>[] graph) {35 final int n = graph.length;36 List<List<Integer>> res = new ArrayList<>();37 38 for (int subsetSize = 0; subsetSize <= n; ++subsetSize) {39 boolean[] combination = new boolean[n];40 Arrays.fill(combination, n - subsetSize, n, true);41 do {42 List<Integer> doubledSubset = new ArrayList<>();43 for (int i = 0; i < n; i++)44 if (combination[i])45 doubledSubset.add(i);46 if (!hasCycleSkipping(graph, new HashSet<>(doubledSubset)))47 res.add(doubledSubset);48 } while (nextPermutation(combination));49 if (!res.isEmpty())50 return res;51 }52 return res;53 }54 55 56 57 private boolean hasCycleSkipping(List<Integer>[] graph, Set<Integer> doubledSubset) {58 State[] states = new State[graph.length];59 for (int i = 0; i < graph.length; ++i)60 if (hasCycle(graph, i, states, doubledSubset))61 return true;62 return false;63 }64 65 private boolean hasCycle(List<Integer>[] graph, int u, State[] states,66 Set<Integer> doubledSubset) {67 if (states[u] == State.VISITING)68 return true;69 if (states[u] == State.VISITED)70 return false;71 states[u] = State.VISITING;72 if (!doubledSubset.contains(u))73 for (final int v : graph[u])74 if (!doubledSubset.contains(v) && hasCycle(graph, v, states, doubledSubset))75 return true;76 states[u] = State.VISITED;77 return false;78 }79 80 private List<int[]> getEdges(String[] words) {81 List<int[]> edges = new ArrayList<>();82 for (final String word : words)83 edges.add(new int[] {word.charAt(0) - 'a', word.charAt(1) - 'a'});84 return edges;85 }86 87 private List<Integer> getNodes(List<int[]> edges) {88 TreeSet<Integer> nodes = new TreeSet<>();89 for (int[] edge : edges) {90 final int u = edge[0];91 final int v = edge[1];92 nodes.add(u);93 nodes.add(v);94 }95 return new ArrayList<>(nodes);96 }97 98 private int[] getLetterToIndex(List<Integer> nodes) {99 int[] letterToIndex = new int[26];100 for (int i = 0; i < nodes.size(); ++i)101 letterToIndex[nodes.get(i)] = i;102 return letterToIndex;103 }104 105 private boolean nextPermutation(boolean[] arr) {106 final int n = arr.length;107 108 109 int i;110 for (i = n - 2; i >= 0; --i)111 if (!arr[i] && arr[i + 1])112 break;113 114 115 if (i < 0)116 return false;117 118 119 for (int j = n - 1; j > i; --j)120 if (arr[j] && !arr[i]) {121 swap(arr, i, j);122 break;123 }124 125 126 reverse(arr, i + 1, n - 1);127 return true;128 }129 130 private void reverse(boolean[] arr, int l, int r) {131 while (l < r)132 swap(arr, l++, r--);133 }134 135 private void swap(boolean[] arr, int i, int j) {136 boolean temp = arr[i];137 arr[i] = arr[j];138 arr[j] = temp;139 }140}141