Skip to content

Commit 9966d60

Browse files
committed
feat: add solutions to lc problem: No.0943
No.0943.Find the Shortest Superstring
1 parent 8ca5c6e commit 9966d60

File tree

6 files changed

+757
-2
lines changed

6 files changed

+757
-2
lines changed

solution/0900-0999/0943.Find the Shortest Superstring/README.md

+266-1
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,287 @@
4040

4141
<!-- 这里可写通用的实现逻辑 -->
4242

43+
**方法一:状态压缩 + 动态规划**
44+
45+
由于题目中字符串数组 `words` 的长度不超过 12,因此可以使用状态压缩的方法来表示字符串数组中的每个字符串是否被选中。
46+
47+
定义 $dp[i][j]$ 表示字符串当前选中状态为 $i$,且最后一个选中的字符串为 $s[j]$ 时,字符串重叠部分的最大长度。其中 $i$ 的二进制表示中的第 $j$ 位为 $1$ 表示字符串 $s[j]$ 被选中,为 $0$ 表示字符串 $s[j]$ 未被选中。重叠部分达到最大时,最终得到的字符串最短。我们只要求出重叠部分的最大值以及对应的字符串 $s[j]$,记录每一步状态转移,就能够逆推出最终的字符串。
48+
49+
字符串两两之间的重叠部分长度可以预处理出来,存储在二维数组 $g$ 中,其中 $g[i][j]$ 表示字符串 $s[i]$ 和字符串 $s[j]$ 之间的重叠部分长度。
50+
51+
动态规划的状态转移方程如下:
52+
53+
$$
54+
dp[i][j] = \max_{k \in \{0, 1, \cdots, n - 1\}} \{dp[i - 2^j][k] + g[k][j]\}
55+
$$
56+
57+
时间复杂度 $O(2^n \times n^2)$,空间复杂度 $O(2^n \times n)$。其中 $n$ 为字符串数组 `words` 的长度。
58+
4359
<!-- tabs:start -->
4460

4561
### **Python3**
4662

4763
<!-- 这里可写当前语言的特殊实现逻辑 -->
4864

4965
```python
50-
66+
class Solution:
67+
def shortestSuperstring(self, words: List[str]) -> str:
68+
n = len(words)
69+
g = [[0] * n for _ in range(n)]
70+
for i, a in enumerate(words):
71+
for j, b in enumerate(words):
72+
if i != j:
73+
for k in range(min(len(a), len(b)), 0, -1):
74+
if a[-k:] == b[:k]:
75+
g[i][j] = k
76+
break
77+
dp = [[0] * n for _ in range(1 << n)]
78+
p = [[-1] * n for _ in range(1 << n)]
79+
for i in range(1 << n):
80+
for j in range(n):
81+
if (i >> j) & 1:
82+
pi = i ^ (1 << j)
83+
for k in range(n):
84+
if (pi >> k) & 1:
85+
v = dp[pi][k] + g[k][j]
86+
if v > dp[i][j]:
87+
dp[i][j] = v
88+
p[i][j] = k
89+
j = 0
90+
for i in range(n):
91+
if dp[-1][i] > dp[-1][j]:
92+
j = i
93+
arr = [j]
94+
i = (1 << n) - 1
95+
while p[i][j] != -1:
96+
i, j = i ^ (1 << j), p[i][j]
97+
arr.append(j)
98+
arr = arr[::-1]
99+
vis = set(arr)
100+
arr.extend([j for j in range(n) if j not in vis])
101+
ans = [words[arr[0]]] + [words[j][g[i][j] :] for i, j in pairwise(arr)]
102+
return ''.join(ans)
51103
```
52104

53105
### **Java**
54106

55107
<!-- 这里可写当前语言的特殊实现逻辑 -->
56108

57109
```java
110+
class Solution {
111+
public String shortestSuperstring(String[] words) {
112+
int n = words.length;
113+
int[][] g = new int[n][n];
114+
for (int i = 0; i < n; ++i) {
115+
String a = words[i];
116+
for (int j = 0; j < n; ++j) {
117+
String b = words[j];
118+
if (i != j) {
119+
for (int k = Math.min(a.length(), b.length()); k > 0; --k) {
120+
if (a.substring(a.length() - k).equals(b.substring(0, k))) {
121+
g[i][j] = k;
122+
break;
123+
}
124+
}
125+
}
126+
}
127+
}
128+
int[][] dp = new int[1 << n][n];
129+
int[][] p = new int[1 << n][n];
130+
for (int i = 0; i < 1 << n; ++i) {
131+
Arrays.fill(p[i], -1);
132+
for (int j = 0; j < n; ++j) {
133+
if (((i >> j) & 1) == 1) {
134+
int pi = i ^ (1 << j);
135+
for (int k = 0; k < n; ++k) {
136+
if (((pi >> k) & 1) == 1) {
137+
int v = dp[pi][k] + g[k][j];
138+
if (v > dp[i][j]) {
139+
dp[i][j] = v;
140+
p[i][j] = k;
141+
}
142+
}
143+
}
144+
}
145+
}
146+
}
147+
int j = 0;
148+
for (int i = 0; i < n; ++i) {
149+
if (dp[(1 << n) - 1][i] > dp[(1 << n) - 1][j]) {
150+
j = i;
151+
}
152+
}
153+
List<Integer> arr = new ArrayList<>();
154+
arr.add(j);
155+
for (int i = (1 << n) - 1; p[i][j] != -1;) {
156+
int k = i;
157+
i ^= (1 << j);
158+
j = p[k][j];
159+
arr.add(j);
160+
}
161+
Set<Integer> vis = new HashSet<>(arr);
162+
for (int i = 0; i < n; ++i) {
163+
if (!vis.contains(i)) {
164+
arr.add(i);
165+
}
166+
}
167+
Collections.reverse(arr);
168+
StringBuilder ans = new StringBuilder(words[arr.get(0)]);
169+
for (int i = 1; i < n; ++i) {
170+
int k = g[arr.get(i - 1)][arr.get(i)];
171+
ans.append(words[arr.get(i)].substring(k));
172+
}
173+
return ans.toString();
174+
}
175+
}
176+
```
177+
178+
### **C++**
179+
180+
```cpp
181+
class Solution {
182+
public:
183+
string shortestSuperstring(vector<string>& words) {
184+
int n = words.size();
185+
vector<vector<int>> g(n, vector<int>(n));
186+
for (int i = 0; i < n; ++i) {
187+
auto a = words[i];
188+
for (int j = 0; j < n; ++j) {
189+
auto b = words[j];
190+
if (i != j) {
191+
for (int k = min(a.size(), b.size()); k > 0; --k) {
192+
if (a.substr(a.size() - k) == b.substr(0, k)) {
193+
g[i][j] = k;
194+
break;
195+
}
196+
}
197+
}
198+
}
199+
}
200+
vector<vector<int>> dp(1 << n, vector<int>(n));
201+
vector<vector<int>> p(1 << n, vector<int>(n, -1));
202+
for (int i = 0; i < 1 << n; ++i) {
203+
for (int j = 0; j < n; ++j) {
204+
if ((i >> j) & 1) {
205+
int pi = i ^ (1 << j);
206+
for (int k = 0; k < n; ++k) {
207+
if ((pi >> k) & 1) {
208+
int v = dp[pi][k] + g[k][j];
209+
if (v > dp[i][j]) {
210+
dp[i][j] = v;
211+
p[i][j] = k;
212+
}
213+
}
214+
}
215+
}
216+
}
217+
}
218+
int j = 0;
219+
for (int i = 0; i < n; ++i) {
220+
if (dp[(1 << n) - 1][i] > dp[(1 << n) - 1][j]) {
221+
j = i;
222+
}
223+
}
224+
vector<int> arr = {j};
225+
for (int i = (1 << n) - 1; p[i][j] != -1;) {
226+
int k = i;
227+
i ^= (1 << j);
228+
j = p[k][j];
229+
arr.push_back(j);
230+
}
231+
unordered_set<int> vis(arr.begin(), arr.end());
232+
for (int i = 0; i < n; ++i) {
233+
if (!vis.count(i)) {
234+
arr.push_back(i);
235+
}
236+
}
237+
reverse(arr.begin(), arr.end());
238+
string ans = words[arr[0]];
239+
for (int i = 1; i < n; ++i) {
240+
int k = g[arr[i - 1]][arr[i]];
241+
ans += words[arr[i]].substr(k);
242+
}
243+
return ans;
244+
}
245+
};
246+
```
247+
248+
### **Go**
249+
250+
```go
251+
func shortestSuperstring(words []string) string {
252+
n := len(words)
253+
g := make([][]int, n)
254+
for i, a := range words {
255+
g[i] = make([]int, n)
256+
for j, b := range words {
257+
if i != j {
258+
for k := min(len(a), len(b)); k > 0; k-- {
259+
if a[len(a)-k:] == b[:k] {
260+
g[i][j] = k
261+
break
262+
}
263+
}
264+
}
265+
}
266+
}
267+
dp := make([][]int, 1<<n)
268+
p := make([][]int, 1<<n)
269+
for i := 0; i < 1<<n; i++ {
270+
dp[i] = make([]int, n)
271+
p[i] = make([]int, n)
272+
for j := 0; j < n; j++ {
273+
p[i][j] = -1
274+
if ((i >> j) & 1) == 1 {
275+
pi := i ^ (1 << j)
276+
for k := 0; k < n; k++ {
277+
if ((pi >> k) & 1) == 1 {
278+
v := dp[pi][k] + g[k][j]
279+
if v > dp[i][j] {
280+
dp[i][j] = v
281+
p[i][j] = k
282+
}
283+
}
284+
}
285+
}
286+
}
287+
}
288+
j := 0
289+
for i := 0; i < n; i++ {
290+
if dp[(1<<n)-1][i] > dp[(1<<n)-1][j] {
291+
j = i
292+
}
293+
}
294+
arr := []int{j}
295+
vis := make([]bool, n)
296+
vis[j] = true
297+
for i := (1 << n) - 1; p[i][j] != -1; {
298+
k := i
299+
i ^= (1 << j)
300+
j = p[k][j]
301+
arr = append(arr, j)
302+
vis[j] = true
303+
}
304+
for i := 0; i < n; i++ {
305+
if !vis[i] {
306+
arr = append(arr, i)
307+
}
308+
}
309+
ans := &strings.Builder{}
310+
ans.WriteString(words[arr[n-1]])
311+
for i := n - 2; i >= 0; i-- {
312+
k := g[arr[i+1]][arr[i]]
313+
ans.WriteString(words[arr[i]][k:])
314+
}
315+
return ans.String()
316+
}
58317
318+
func min(a, b int) int {
319+
if a < b {
320+
return a
321+
}
322+
return b
323+
}
59324
```
60325

61326
### **...**

0 commit comments

Comments
 (0)