Find the Shortest Superstring

update Feb 18 2019, 20:15

LeetCodearrow-up-right

Given an array A of strings, find any smallest string that contains each string in A as a substring.

We may assume that no string in A is substring of another string in A.

Example 1:

Input: ["alex","loves","leetcode"]
Output: "alexlovesleetcode"
Explanation: All permutations of "alex","loves","leetcode" would also be accepted.

Example 2:

Input: ["catg","ctaagt","gcta","ttca","atgcatc"]
Output: "gctaagttcatgcatc"

Note:

  1. 1 <= A.length <= 12

  2. 1 <= A[i].length <= 20

Basic Idea:

先上花花酱讲题的链接:https://www.youtube.com/watch?v=u_Wc4jwrp3Qarrow-up-right

这是他视频中的slide截图,感觉很不错:

这道题本质上可以被看作哈密顿路径问题(hamiltonian path),因为我们可以将这道题的定义进行抽象:给定N个节点,每对节点之间的边有一定的weight,要求找到一条路径经过每个节点有且只有一次,且该路径总weight最小。

具体在这里,string a 和 string b 之间的 weight 就是将 b append 到 a 之后需要增加的长度。

这种问题brute force的做法是DFS,时间复杂度为 O(N!),如果使用DP,可以利用更多的空间而使时间优化到 O(2^N)级别。这里的优化其实是显著的,Leetcode中 O(N!) 复杂度大概最多做到 N=10,而 O(2^N) 是可以做到 N=20 的。

具体的方法是DP,比较特殊的是我们需要DP数组记录不同的状态。其实在搜索路径过程中每个状态可以用它已经经过的Nodes和结尾的Node来唯一确定。只要这两者确定,我们不需要关心这些被经过的Node之间的相互顺序,这样就将排列问题优化为了一个组合问题。一般来说用一个int作为bitmap就可以表示当前路径已经经过的node(将相应位置标记为1),所以这里用到的dp数组是 int dp[1<<N][N][2]dp[s][i][0]表示在当前已选择node集合为 s 并且该路径目前以 i 结尾的最短长度, dp[s][i][1] 则记录上一个node的index用来最终恢复路径。

Java Code:

Last updated