943. Find the Shortest Superstring
https://leetcode.com/problems/find-the-shortest-superstring/description/
给定一串字符串A,找出现了A中所有字符串的最短字符串。最短肯定是尽量让两个词有overlap,而找出访问了所有结点的最短路径,即汉密尔顿问题,是NP-hard,目前只可能有指数级别的解。纯暴力DFS是找出所有可能的遍历路径,是阶乘级别的。但实际上这道题用DP可以降到指数级别,因为它满足DP的无后效性(马尔可夫): 只用知道哪些已经遍历过了,且最后结点是i, 而不用实时追踪具体怎么走到的i。 由于题目要求返回字符串,不止是长度,因此还需要记录最优是怎么走的。
参考自花花。
/*
* @lc app=leetcode id=943 lang=cpp
*
* [943] Find the Shortest Superstring
*
* https://leetcode.com/problems/find-the-shortest-superstring/description/
*
* algorithms
* Hard (38.95%)
* Likes: 199
* Dislikes: 57
* Total Accepted: 6K
* Total Submissions: 15.3K
* Testcase Example: '["alex","loves","leetcode"]'
*
* 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 <= A.length <= 12
* 1 <= A[i].length <= 20
*
*
*
*
*
*/
class Solution {
public:
string shortestSuperstring(vector<string>& A) {
const auto dist = [](const string &a, const string &b) {
int d = b.length();
for (int k = 1; k <= min(a.length(), b.length()); ++k) {
if (a.substr(a.size() - k) == b.substr(0, k)) d = b.length() - k;
}
return d;
};
const int N = A.size();
vector<vector<int>> g(N, vector<int>(N));
for (int i = 0; i < N; ++i) {
for (int j = i + 1; j < N; ++j) {
g[i][j] = dist(A[i], A[j]);
g[j][i] = dist(A[j], A[i]);
}
}
// <哪些被访问过的状态,末尾>
vector<vector<int>> dp(1 << N, vector<int>(N, INT_MAX / 2));
vector<vector<int>> parent(1 << N, vector<int>(N, -1));
for (int i = 0; i < N; ++i) dp[1 << i][i] = A[i].length();
for (int s = 1; s < (1 << N); ++s) {
for (int i = 0; i < N; ++i) {
// i没有访问过,跳过
if (!(s & (1 << i))) continue;
// i 位置空,即上一状态
int prev = s - (1 << i);
for (int j = 0; j < N; ++j) {
if (dp[prev][j] + g[j][i] < dp[s][i]) {
dp[s][i] = dp[prev][j] + g[j][i];
parent[s][i] = j;
}
}
}
}
auto it = min_element(begin(dp.back()), end(dp.back()));
int cur = it - begin(dp.back());
int s = (1 << N) - 1;
string res;
while (s) {
int prev = parent[s][cur];
if (prev < 0) res = A[cur] + res;
else res = A[cur].substr(A[cur].length() - g[prev][cur]) + res;
s &= ~(1 << cur);
cur = prev;
}
return res;
}
};
Last updated
Was this helpful?