用 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

更新於: 2020-06-04

307 次瀏覽

開啟你的 職業生涯

透過完成課程獲得認證

開始學習
廣告
© . All rights reserved.