Skip to content

Commit 0012f75

Browse files
committed
Improved task 3435
1 parent 9d07bce commit 0012f75

File tree

1 file changed

+80
-158
lines changed
  • src/main/java/g3401_3500/s3435_frequencies_of_shortest_supersequences

1 file changed

+80
-158
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,192 +1,114 @@
11
package g3401_3500.s3435_frequencies_of_shortest_supersequences;
22

33
// #Hard #Array #String #Bit_Manipulation #Graph #Enumeration #Topological_Sort
4-
// #2025_01_27_Time_751_(100.00%)_Space_49.95_(100.00%)
4+
// #2025_01_29_Time_16_(95.35%)_Space_45.52_(93.02%)
55

66
import java.util.ArrayList;
77
import java.util.Arrays;
8-
import java.util.Collections;
9-
import java.util.HashMap;
8+
import java.util.HashSet;
109
import java.util.List;
11-
import java.util.Map;
10+
import java.util.Set;
1211

1312
public class Solution {
14-
public List<List<Integer>> supersequences(String[] wordsArray) {
15-
List<String> words = new ArrayList<>(Arrays.asList(wordsArray));
16-
Collections.sort(words);
17-
int[] bg = new int[26];
18-
int[] ed = new int[26];
19-
Arrays.fill(bg, -1);
20-
Arrays.fill(ed, 0);
21-
int[] tans = initializeArrays(words);
22-
List<String> wtc = buildWtcList(words, tans);
23-
updateBgEdArrays(wtc, bg, ed);
24-
List<List<Integer>> ans = new ArrayList<>();
25-
if (wtc.isEmpty()) {
26-
ans.add(convertArrayToList(tans));
27-
} else {
28-
processNonEmptyWtc(wtc, tans, bg, ed, ans);
29-
}
30-
return ans;
31-
}
32-
33-
private int[] initializeArrays(List<String> words) {
34-
Map<String, Boolean> mp = new HashMap<>();
35-
Map<Character, Boolean> mp2 = new HashMap<>();
36-
for (String word : words) {
37-
mp.put(word, true);
38-
mp2.put(word.charAt(0), true);
39-
mp2.put(word.charAt(1), true);
13+
private int m;
14+
private int forcedMask;
15+
private int[] adj;
16+
private char[] idxToChar = new char[26];
17+
private int[] charToIdx = new int[26];
18+
private boolean[] used = new boolean[26];
19+
20+
public List<List<Integer>> supersequences(String[] words) {
21+
Arrays.fill(charToIdx, -1);
22+
for (String w : words) {
23+
used[w.charAt(0) - 'a'] = true;
24+
used[w.charAt(1) - 'a'] = true;
4025
}
41-
int[] tans = new int[26];
42-
for (char c = 'a'; c <= 'z'; c++) {
43-
String aux = "" + c + c;
44-
if (mp.containsKey(aux)) {
45-
tans[c - 'a'] = 2;
46-
} else if (mp2.containsKey(c)) {
47-
tans[c - 'a'] = 1;
26+
// Map each used letter to an index [0..m-1]
27+
for (int c = 0; c < 26; c++) {
28+
if (used[c]) {
29+
idxToChar[m] = (char) (c + 'a');
30+
charToIdx[c] = m++;
4831
}
4932
}
50-
return tans;
51-
}
52-
53-
private List<String> buildWtcList(List<String> words, int[] tans) {
54-
List<String> wtc = new ArrayList<>();
55-
for (String word : words) {
56-
if (tans[word.charAt(0) - 'a'] != 2 && tans[word.charAt(1) - 'a'] != 2) {
57-
wtc.add(word);
33+
adj = new int[m];
34+
// Build graph and record forced duplicates
35+
for (String w : words) {
36+
int u = charToIdx[w.charAt(0) - 'a'];
37+
int v = charToIdx[w.charAt(1) - 'a'];
38+
if (u == v) {
39+
forcedMask |= (1 << u);
40+
} else {
41+
adj[u] |= (1 << v);
5842
}
5943
}
60-
return wtc;
61-
}
62-
63-
private void updateBgEdArrays(List<String> wtc, int[] bg, int[] ed) {
64-
for (String word : wtc) {
65-
int l = word.charAt(0) - 'a';
66-
if (bg[l] == -1) {
67-
bg[l] = wtc.indexOf(word);
44+
// Try all supersets of forcedMask; keep those that kill all cycles
45+
int best = 9999;
46+
List<Integer> goodSets = new ArrayList<>();
47+
for (int s = 0; s < (1 << m); s++) {
48+
if ((s & forcedMask) != forcedMask) {
49+
continue;
6850
}
69-
ed[l] = wtc.indexOf(word);
70-
}
71-
}
72-
73-
private void processNonEmptyWtc(
74-
List<String> wtc, int[] tans, int[] bg, int[] ed, List<List<Integer>> ans) {
75-
List<Integer> ns = buildNsList(tans);
76-
List<Integer> gm = buildGmList(wtc, tans, bg, ed, ns);
77-
int minb = findMinBits(gm);
78-
addMinimalAnswers(gm, minb, ns, tans, ans);
79-
}
80-
81-
private List<Integer> buildNsList(int[] tans) {
82-
List<Integer> ns = new ArrayList<>();
83-
for (int i = 0; i < 26; i++) {
84-
if (tans[i] == 1) {
85-
ns.add(i);
51+
int size = Integer.bitCount(s);
52+
if (size > best) {
53+
continue;
8654
}
87-
}
88-
return ns;
89-
}
90-
91-
private List<Integer> buildGmList(
92-
List<String> wtc, int[] tans, int[] bg, int[] ed, List<Integer> ns) {
93-
List<Integer> gm = new ArrayList<>();
94-
for (int i = 0; i < (1 << ns.size()); i++) {
95-
if (isValidConfiguration(i, wtc, tans, bg, ed, ns)) {
96-
gm.add(i);
55+
if (!hasCycle(s)) {
56+
if (size < best) {
57+
best = size;
58+
goodSets.clear();
59+
}
60+
goodSets.add(s);
9761
}
9862
}
99-
return gm;
100-
}
101-
102-
private boolean isValidConfiguration(
103-
int i, List<String> wtc, int[] tans, int[] bg, int[] ed, List<Integer> ns) {
104-
int[] indg = new int[26];
105-
updateTansForConfiguration(i, tans, ns);
106-
for (String word : wtc) {
107-
if (tans[word.charAt(0) - 'a'] != 2 && tans[word.charAt(1) - 'a'] != 2) {
108-
indg[word.charAt(1) - 'a']++;
63+
// Build distinct freq arrays from these sets
64+
Set<String> seen = new HashSet<>();
65+
List<List<Integer>> ans = new ArrayList<>();
66+
for (int s : goodSets) {
67+
int[] freq = new int[26];
68+
for (int i = 0; i < m; i++) {
69+
freq[idxToChar[i] - 'a'] = ((s & (1 << i)) != 0) ? 2 : 1;
10970
}
110-
}
111-
List<Integer> chk = buildChkList(indg, tans);
112-
processChkList(chk, wtc, tans, bg, ed, indg);
113-
return Arrays.stream(indg).max().orElse(0) == 0;
114-
}
115-
116-
private void updateTansForConfiguration(int i, int[] tans, List<Integer> ns) {
117-
for (int j = 0; j < ns.size(); j++) {
118-
if ((i & (1 << j)) != 0) {
119-
tans[ns.get(j)] = 2;
120-
} else {
121-
tans[ns.get(j)] = 1;
71+
String key = Arrays.toString(freq);
72+
if (seen.add(key)) {
73+
List<Integer> tmp = new ArrayList<>();
74+
for (int f : freq) {
75+
tmp.add(f);
76+
}
77+
ans.add(tmp);
12278
}
12379
}
80+
return ans;
12481
}
12582

126-
private List<Integer> buildChkList(int[] indg, int[] tans) {
127-
List<Integer> chk = new ArrayList<>();
128-
for (int j = 0; j < 26; j++) {
129-
if (indg[j] == 0 && tans[j] == 1) {
130-
chk.add(j);
83+
private boolean hasCycle(int mask) {
84+
int[] color = new int[m];
85+
for (int i = 0; i < m; i++) {
86+
if (((mask >> i) & 1) == 0 && color[i] == 0) {
87+
if (dfs(i, color, mask)) {
88+
return true;
89+
}
13190
}
13291
}
133-
return chk;
92+
return false;
13493
}
13594

136-
private void processChkList(
137-
List<Integer> chk, List<String> wtc, int[] tans, int[] bg, int[] ed, int[] indg) {
138-
while (!chk.isEmpty()) {
139-
int u = chk.remove(chk.size() - 1);
140-
if (bg[u] == -1) {
95+
private boolean dfs(int u, int[] color, int mask) {
96+
color[u] = 1;
97+
int nxt = adj[u];
98+
while (nxt != 0) {
99+
int v = Integer.numberOfTrailingZeros(nxt);
100+
nxt &= (nxt - 1);
101+
if (((mask >> v) & 1) == 1) {
141102
continue;
142103
}
143-
for (int j = bg[u]; j <= ed[u]; j++) {
144-
int l = wtc.get(j).charAt(1) - 'a';
145-
if (tans[l] == 2) {
146-
continue;
147-
}
148-
indg[l]--;
149-
if (indg[l] == 0) {
150-
chk.add(l);
151-
}
104+
if (color[v] == 1) {
105+
return true;
152106
}
153-
}
154-
}
155-
156-
private int findMinBits(List<Integer> gm) {
157-
int minb = 20;
158-
for (int x : gm) {
159-
minb = Math.min(minb, countSetBits(x));
160-
}
161-
return minb;
162-
}
163-
164-
private void addMinimalAnswers(
165-
List<Integer> gm, int minb, List<Integer> ns, int[] tans, List<List<Integer>> ans) {
166-
for (int x : gm) {
167-
if (countSetBits(x) == minb) {
168-
updateTansForConfiguration(x, tans, ns);
169-
ans.add(convertArrayToList(tans));
107+
if (color[v] == 0 && dfs(v, color, mask)) {
108+
return true;
170109
}
171110
}
172-
}
173-
174-
private int countSetBits(int x) {
175-
int count = 0;
176-
while (x > 0) {
177-
if ((x & 1) != 0) {
178-
count++;
179-
}
180-
x >>= 1;
181-
}
182-
return count;
183-
}
184-
185-
private List<Integer> convertArrayToList(int[] array) {
186-
List<Integer> list = new ArrayList<>();
187-
for (int num : array) {
188-
list.add(num);
189-
}
190-
return list;
111+
color[u] = 2;
112+
return false;
191113
}
192114
}

0 commit comments

Comments
 (0)