用 C++ 查找最短超串
假设我们有一个字符串数组 A,我们需要找到一个包含 A 中每个字符串作为子字符串的最小字符串。我们还可以假设 A 中没有一个字符串是另一个字符串的子字符串。
因此,如果输入类似于 ["dbsh","dsbbhs","hdsb","ssdb","bshdbsd"],则输出将为 "hdsbbhssdbshdbsd"
为了解决这个问题,我们将遵循以下步骤:
定义一个函数 calc(),它将接收 a、b 作为参数。
从 i := 0 开始,当 i < a 的大小,更新 (i 加 1),执行:
如果从索引 i 到结尾的 a 的子字符串位于 b 的开头,则:
返回 b 的大小 - a 的大小 + i
返回 b 的大小
从主方法开始,执行以下步骤
ret := 空字符串
n := A 的大小
定义一个大小为 n x n 的二维数组 graph
从 j := 0 开始,当 j < n,更新 (j 加 1),执行:
graph[i, j] := calc(A[i], A[j])
graph[j, i] := calc(A[j], A[i])
定义一个大小为 2^n x n 的数组 dp。
定义一个大小为 2^n x n 的数组 path。
minVal := inf
last := -1
从 i := 0 开始,当 i < 2^n,更新 (i 加 1),执行:
从 j := 0 开始,当 j < n,更新 (j 加 1),执行:
dp[i, j] := inf
从 i := 0 开始,当 i < 2^n,更新 (i 加 1),执行:
从 j := 0 开始,当 j < n,更新 (j 加 1),执行:
如果 i AND 2^j 非零,则
prev := i ^ (2^j)
如果 prev 等于 0,则:
dp[i, j] := A[j] 的大小
否则
从 k := 0 开始,当 k < n,更新 (k 加 1),执行:
如果 prev AND 2^k 且 df[prev,k] 不为 inf 且 df[prev,k] + graph[k,j] < dp[i,j],则
dp[i, j] := dp[prev, k] + graph[k, j]
path[i, j] := k
如果 i 等于 2^n - 1 且 dp[i, j] < minVal,则:
minVal := dp[i, j]
last := j
curr := 2^n - 1
定义一个栈 st
当 curr > 0 时,执行:
将 last 插入 st
temp := curr
curr := curr - (2^last)
last := path[temp, last]
i := st 的顶部元素
从 st 中删除元素
ret := ret + A[i]
当 (st 不为空) 时,执行:
j := st 的顶部元素
从 st 中删除元素
ret := ret 连接 A[j] 从 (A[j] 的大小 - graph[i,j] 到结尾) 的子字符串
i := j
返回 ret
让我们查看以下实现以更好地理解:
示例
#include <bits/stdc++.h> using namespace std; class Solution { public: int calc(string& a, string& b){ for (int i = 0; i < a.size(); i++) { if (b.find(a.substr(i)) == 0) { return b.size() - a.size() + i; } } return (int)b.size(); } string shortestSuperstring(vector<string>& A){ string ret = ""; int n = A.size(); vector<vector<int> > graph(n, vector<int>(n)); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { graph[i][j] = calc(A[i], A[j]); graph[j][i] = calc(A[j], A[i]); } } int dp[1 << n][n]; int path[1 << n][n]; int minVal = INT_MAX; int last = -1; for (int i = 0; i < (1 << n); i++) for (int j = 0; j < n; j++) dp[i][j] = INT_MAX; for (int i = 1; i < (1 << n); i++) { for (int j = 0; j < n; j++) { if ((i & (1 << j))) { int prev = i ^ (1 << j); if (prev == 0) { dp[i][j] = A[j].size(); } else { for (int k = 0; k < n; k++) { if ((prev & (1 << k)) && dp[prev][k] != INT_MAX && dp[prev][k] + graph[k][j] < dp[i][j]) { dp[i][j] = dp[prev][k] + graph[k][j]; path[i][j] = k; } } } } if (i == (1 << n) - 1 && dp[i][j] < minVal) { minVal = dp[i][j]; last = j; } } } int curr = (1 << n) - 1; stack<int> st; while (curr > 0) { st.push(last); int temp = curr; curr -= (1 << last); last = path[temp][last]; } int i = st.top(); st.pop(); ret += A[i]; while (!st.empty()) { int j = st.top(); st.pop(); ret += (A[j].substr(A[j].size() - graph[i][j])); i = j; } return ret; } }; main(){ Solution ob; vector<string> v = {"dbsh","dsbbhs","hdsb","ssdb","bshdbsd"}; cout << (ob.shortestSuperstring(v)); }
输入
{"dbsh","dsbbhs","hdsb","ssdb","bshdbsd"}
输出
hdsbbhssdbshdbsd