We define the lcp matrix of any 0-indexed string word of n lowercase English letters as an n x n grid such that:
lcp[i][j] is equal to the length of the longest common prefix between the substrings word[i,n-1] and word[j,n-1].
Given an n x n matrix lcp, return the alphabetically smallest string
word that corresponds to lcp. If there is no such string, return an empty string.
A string a is lexicographically smaller than a string b (of the same length) if in the first position where a and b differ, string a has a letter that appears earlier in the alphabet than the corresponding letter in
b. For example, "aabd" is lexicographically smaller than "aaca" because the first position they differ is at the third letter, and 'b' comes before
'c'.
Input: lcp =[[4,0,2,0],[0,3,0,1],[2,0,2,0],[0,1,0,1]]Output: "abab"Explanation: lcp corresponds to any 4 letter string with two alternating letters. The lexicographically smallest of them is"abab".
Input: lcp =[[4,3,2,1],[3,3,2,1],[2,2,2,1],[1,1,1,1]]Output: "aaaa"Explanation: lcp corresponds to any 4 letter string with a single distinct letter. The lexicographically smallest of them is"aaaa".
Input: lcp =[[4,3,2,1],[3,3,2,1],[2,2,2,1],[1,1,1,3]]Output: ""Explanation: lcp[3][3] cannot be equal to 3 since word[3,...,3] consists of only a single letter; Thus, no answer exists.
We want to construct the lexicographically smallest string that matches the given LCP matrix. If lcp[i][j] > 0, then word[i] == word[j]. We can use union-find to group indices that must have the same character. Then, assign the smallest possible character to each group, and check if the constructed string matches the LCP matrix.
classSolution {
public String findTheString(int[][] lcp) {
int n = lcp.length;
int[] p =newint[n];
for (int i = 0; i < n; ++i) p[i]= i;
java.util.function.IntUnaryOperator find =new java.util.function.IntUnaryOperator() {
publicintapplyAsInt(int x) { return p[x]== x ? x : (p[x]= applyAsInt(p[x])); }
};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (lcp[i][j]> 0) p[find.applyAsInt(i)]= find.applyAsInt(j);
}
}
Map<Integer, Character> g2c =new HashMap<>();
int gid = 0;
char[] ans =newchar[n];
for (int i = 0; i < n; ++i) {
int root = find.applyAsInt(i);
if (!g2c.containsKey(root)) {
if (gid >= 26) return"";
g2c.put(root, (char)('a'+ gid++));
}
ans[i]= g2c.get(root);
}
// Validatefor (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
int l = 0;
while (i + l < n && j + l < n && ans[i + l]== ans[j + l]) l++;
if (lcp[i][j]!= l) return"";
}
}
returnnew String(ans);
}
}
classSolution {
funfindTheString(lcp: Array<IntArray>): String {
val n = lcp.size
val p = IntArray(n) { it }
funfind(x: Int): Int {
if (p[x] != x) p[x] = find(p[x])
return p[x]
}
for (i in0 until n) {
for (j in0 until n) {
if (lcp[i][j] > 0) p[find(i)] = find(j)
}
}
val g2c = mutableMapOf<Int, Char>()
var gid = 0val ans = CharArray(n)
for (i in0 until n) {
val root = find(i)
if (g2c[root] ==null) {
if (gid >=26) return"" g2c[root] = ('a' + gid++)
}
ans[i] = g2c[root]!! }
// Validate
for (i in0 until n) {
for (j in0 until n) {
var l = 0while (i + l < n && j + l < n && ans[i + l] == ans[j + l]) l++if (lcp[i][j] != l) return"" }
}
return String(ans)
}
}
classSolution:
deffindTheString(self, lcp: list[list[int]]) -> str:
n = len(lcp)
p = list(range(n))
deffind(x):
if p[x] != x:
p[x] = find(p[x])
return p[x]
for i in range(n):
for j in range(n):
if lcp[i][j] >0:
p[find(i)] = find(j)
g2c = {}
gid =0 ans = [''] * n
for i in range(n):
root = find(i)
if root notin g2c:
if gid >=26:
return'' g2c[root] = chr(ord('a') + gid)
gid +=1 ans[i] = g2c[root]
# Validatefor i in range(n):
for j in range(n):
l =0while i + l < n and j + l < n and ans[i + l] == ans[j + l]:
l +=1if lcp[i][j] != l:
return''return''.join(ans)