leetcode

Leetcode Solutions (0x6A73)
git clone https://git.pngu.org/leetcode
Log | Files | Refs | Submodules | README

commit 6a7c91c564b83a756b66ab223861890fb1334410
parent d12256a3a2fc671483042d4c133f87a8c92dcec2
Author: Jack Sangdahl <jack@pngu.org>
Date:   Mon, 15 Dec 2025 15:45:27 -0700

943. find the shortest superstring

Diffstat:
Afind_shortest_superstring.c | 149+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afind_shortest_superstring.py | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 203 insertions(+), 0 deletions(-)

diff --git a/find_shortest_superstring.c b/find_shortest_superstring.c @@ -0,0 +1,149 @@ +// 943. Find the Shortest Superstring +#include "leetcode.h" + +/* + * given an array of strings 'words', return the smallest string that contains + * each string in 'words' as a substring. if there multiple valid strings of the + * smallest length, return any of them. you may assume that no string in 'words' + * is a substring of another string in 'words'. + */ + +struct connection { + char *suffix; + int overlap; +}; + +struct dp_state { + int total_len; + int prev; +}; + +struct connection connect_strings(const char *w1, const char *w2) { + int n = strlen(w1), m = strlen(w2); + struct connection res = {.overlap = 0}; + for (int i = 0; i <= n; i++) { + if (!i) { + res.suffix = (char *)malloc((m + 1) * sizeof(char)); + strcpy(res.suffix, w2); + res.overlap = 0; + } else if (i <= m && !strncmp(w1 + n - i, w2, i)) + if (i > res.overlap) { + res.overlap = i; + free(res.suffix); + res.suffix = (char *)malloc(m - i + 1); + strcpy(res.suffix, w2 + i); + } + } + return res; +} + +void generate_permutation(int *indices, int cnt, int *p1, int *p2, + int *perm_cnt) { + *perm_cnt = 0; + for (int i = 0; i < cnt; i++) + for (int j = 0; j < cnt; j++) + if (i != j) { + p1[*perm_cnt] = indices[i]; + p2[*perm_cnt] = indices[j]; + (*perm_cnt)++; + } +} + +char *shortestSuperstring(char **words, int wordsSize) { + int total = 1 << wordsSize; + struct dp_state **dp = + (struct dp_state **)malloc(total * sizeof(struct dp_state *)); + for (int i = 0; i < total; i++) { + dp[i] = (struct dp_state *)malloc(wordsSize * sizeof(struct dp_state)); + for (int j = 0; j < wordsSize; j++) { + dp[i][j].total_len = INT_MAX; + dp[i][j].prev = -1; + } + } + for (int i = 0; i < wordsSize; i++) { + int mask = 1 << i; + dp[mask][i].total_len = strlen(words[i]); + dp[mask][i].prev = -1; + }; + struct connection **conns = + (struct connection **)malloc(wordsSize * sizeof(struct connection *)); + for (int i = 0; i < wordsSize; i++) { + conns[i] = + (struct connection *)malloc(wordsSize * sizeof(struct connection)); + for (int j = 0; j < wordsSize; j++) + if (i != j) + conns[i][j] = connect_strings(words[i], words[j]); + } + for (int mask = 1; mask < total; mask++) { + int *indices = (int *)malloc(wordsSize * sizeof(int)), cnt = 0; + for (int j = 0; j < wordsSize; j++) + if (mask & (1 << j)) + indices[cnt++] = j; + if (cnt < 2) + continue; + int *p1 = (int *)malloc(cnt * cnt * sizeof(int)); + int *p2 = (int *)malloc(cnt * cnt * sizeof(int)); + int perm_cnt; + generate_permutation(indices, cnt, p1, p2, &perm_cnt); + free(indices); + for (int p = 0; p < perm_cnt; p++) { + int j = p1[p], k = p2[p], prev_mask = mask ^ (1 << j); + if (dp[prev_mask][k].total_len == INT_MAX) + continue; + int new_len = dp[prev_mask][k].total_len + conns[k][j].overlap; + if (new_len < dp[mask][j].total_len) { + dp[mask][j].total_len = new_len; + dp[mask][j].prev = k; + } + } + free(p1); + free(p2); + } + int final_mask = total - 1, best_len = INT_MAX, prev_word = -1; + for (int i = 0; i < wordsSize; i++) { + if (dp[final_mask][i].total_len < best_len) { + best_len = dp[final_mask][i].total_len; + prev_word = i; + } + } + int mask = final_mask, curr = prev_word, prev = dp[mask][curr].prev, + total_len = best_len; + char *ans = (char *)malloc((total_len + 1) * sizeof(char)); + ans[0] = '\0'; + char **parts = (char **)malloc(wordsSize * sizeof(char *)); + int part_cnt = 0; + while (prev != -1) { + parts[part_cnt++] = strdup(conns[prev][curr].suffix); + mask ^= (1 << curr); + curr = prev; + prev = dp[mask][curr].prev; + } + strcpy(ans, words[curr]); + for (int i = part_cnt - 1; i >= 0; i--) { + strcat(ans, parts[i]); + free(parts[i]); + } + free(parts); + for (int i = 0; i < wordsSize; i++) { + for (int j = 0; j < wordsSize; j++) + if (i != j) + free(conns[i][j].suffix); + free(conns[i]); + } + free(conns); + for (int i = 0; i < total; i++) + free(dp[i]); + free(dp); + return ans; +} + +int main() { + char *w1[] = {"alex", "loves", "leetcode"}; + char *w2[] = {"catg", "ctaagt", "gcta", "ttca", "atgcatc"}; + char *ss1 = shortestSuperstring(w1, ARRAY_SIZE(w1)); + char *ss2 = shortestSuperstring(w2, ARRAY_SIZE(w2)); + printf("%s\n", ss1); // expect: alexlovesleetcode + printf("%s\n", ss2); // expect: gctaagttcatgcatc + free(ss1); + free(ss2); +} diff --git a/find_shortest_superstring.py b/find_shortest_superstring.py @@ -0,0 +1,54 @@ +# 943. Find the Shortest Superstring +from functools import lru_cache +from itertools import permutations + +""" +given an array of strings 'words', return the smallest string that contains +each string in 'words' as a substring. if there multiple valid strings of the +smallest length, return any of them. you may assume that no string in 'words' +is a substring of another string in 'words'. +""" + + +class Solution(object): + def shortestSuperstring(self, words): + """ + :type words: List[str] + :rtype: str + """ + + @lru_cache(None) + def connect(w1, w2): + return [ + (w2[i:], len(w2) - i) + for i in range(len(w1) + 1) + if w1[-i:] == w2[:i] or not i + ][-1] + + n = len(words) + dp = [[(float("inf"), -1)] * n for _ in range(1 << n)] + for i in range(n): + dp[1 << i][i] = (len(words[i]), -1) + for mask in range(1 << n): + bits = [j for j in range(n) if mask & 1 << j] + for j, k in permutations(bits, 2): + dp[mask][j] = min( + dp[mask][j], + (dp[mask ^ 1 << j][k][0] + connect(words[k], words[j])[1], k), + ) + mask = (1 << n) - 1 + prev = min(dp[mask]) + last = dp[mask].index(prev) + prev = prev[1] + ans = "" + while prev != -1: + ans = connect(words[prev], words[last])[0] + ans + mask -= 1 << last + prev, last = dp[mask][prev][1], prev + return words[last] + ans + + +if __name__ == "__main__": + obj = Solution() + print(obj.shortestSuperstring(words=["alex", "loves", "leetcode"])) + print(obj.shortestSuperstring(words=["catg", "ctaagt", "gcta", "ttca", "atgcatc"]))