1. 程式人生 > >[Swift Weekly Contest 111]LeetCode943. 最短超級串 | Find the Shortest Superstring

[Swift Weekly Contest 111]LeetCode943. 最短超級串 | Find the Shortest Superstring

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

給定一個字串陣列 A,找到以 A 中每個字串作為子字串的最短字串。

我們可以假設 A 中沒有字串是 A 中另一個字串的子字串。

示例 1:

輸入:["alex","loves","leetcode"]
輸出:"alexlovesleetcode"
解釋:"alex","loves","leetcode" 的所有排列都會被接受。

示例 2:

輸入:["catg","ctaagt","gcta","ttca","atgcatc"]
輸出:"gctaagttcatgcatc"

提示:

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

 100ms

 1 class Solution {
 2     func countSubstr(_ A: [String], _ n: String) -> Int {
 3       var sum = 0
 4       for var s in A {
 5         if
n.contains(s) { 6 sum += s.count 7 } 8 } 9 return sum 10 } 11 func shortestSuperstring(_ Ain: [String]) -> String { 12 var A = Ain 13 while A.count > 1 { 14 var maxC = 0 15 var newStr = "" 16 for var i in 0..<A.count { 17 for var j in 0..<A.count { 18 guard i != j else { 19 continue 20 } 21 if A[i].count == 1 { continue } 22 for var l in 1...A[i].count-1 { 23 if A[j].hasPrefix(A[i].suffix(l)) { 24 let n = A[i] + A[j].suffix(A[j].count - l) 25 let C = countSubstr(A, n) - n.count 26 if C > maxC { 27 maxC = C 28 newStr = n 29 } 30 } 31 } 32 } 33 } 34 if maxC == 0 { 35 newStr = A[0] + A[1] 36 } 37 A.removeAll(where: { newStr.contains($0) }) 38 A.append(newStr) 39 } 40 return A[0] 41 } 42 } 43 44 extension String { 45 func contains(_ find: String) -> Bool{ 46 return self.range(of: find) != nil 47 } 48 }

364ms

  1 class Solution {
  2     func shortestSuperstring(_ A: [String]) -> String {
  3         var N:Int = A.count
  4         
  5         // Populate overlaps
  6         var overlaps:[[Int]] = [[Int]](repeating:[Int](repeating:0,count:N),count:N)
  7         for i in 0..<N
  8         {
  9             for j in 0..<N
 10             {
 11                 if i != j
 12                 {
 13                     var m:Int = min(A[i].count, A[j].count)
 14                     for k in (0...m).reversed()
 15                     {
 16                         if A[i].hasSuffix(A[j].substring(0, k))
 17                         {
 18                             overlaps[i][j] = k
 19                             break
 20                         }
 21                     }
 22                 }
 23             }
 24         }
 25         // dp[mask][i] = most overlap with mask, ending with ith element
 26         var dp:[[Int]] = [[Int]](repeating:[Int](repeating:0,count:N),count:1<<N)
 27         var parent:[[Int]] = [[Int]](repeating:[Int](repeating:-1,count:N),count:1<<N)
 28         for mask in 0..<(1<<N)
 29         {
 30             for bit in 0..<N
 31             {
 32                 if ((mask >> bit) & 1) > 0
 33                 {
 34                     // Let's try to find dp[mask][bit].  Previously, we had
 35                     // a collection of items represented by pmask.
 36                     var pmask:Int = mask ^ (1 << bit)
 37                     if pmask == 0 {continue}
 38                     for i in 0..<N
 39                     {
 40                         if ((pmask >> i) & 1) > 0
 41                         {
 42                             // For each bit i in pmask, calculate the value
 43                             // if we ended with word i, then added word 'bit'.
 44                             var val:Int = dp[pmask][i] + overlaps[i][bit]
 45                             if val > dp[mask][bit]
 46                             {
 47                                 dp[mask][bit] = val
 48                                 parent[mask][bit] = i
 49                             }
 50                         }
 51                     }  
 52                 }
 53             }
 54         }
 55         // # Answer will have length sum(len(A[i]) for i) - max(dp[-1])
 56         // Reconstruct answer, first as a sequence 'perm' representing
 57         // the indices of each word from left to right.
 58         var perm:[Int] = [Int](repeating:0,count:N)
 59         var seen:[Bool] = [Bool](repeating:false,count:N)
 60         var t:Int = 0
 61         var mask:Int = (1 << N) - 1
 62         
 63         // p: the last element of perm (last word written left to right)
 64         var p:Int = 0
 65         for j in 0..<N
 66         {
 67             if dp[(1<<N) - 1][j] > dp[(1<<N) - 1][p]
 68             {
 69                 p = j
 70             }
 71         }
 72         
 73         // Follow parents down backwards path that retains maximum overlap
 74         while (p != -1)
 75         {
 76             perm[t] = p
 77             t += 1
 78             seen[p] = true
 79             var p2:Int = parent[mask][p]
 80             mask ^= 1 << p
 81             p = p2
 82         }        
 83         
 84         // Reverse perm
 85         for i in 0..<(t/2)
 86         {
 87             var v:Int = perm[i]
 88             perm[i] = perm[t-1-i]
 89             perm[t-1-i] = v
 90         }
 91         
 92         // Fill in remaining words not yet added
 93         for i in 0..<N
 94         {
 95             if !seen[i]
 96             {
 97                 perm[t] = i
 98                 t += 1
 99             }
100         }
101         
102         // Reconstruct final answer given perm
103         var ans:String = String(A[perm[0]])
104         for i in 1..<N
105         {
106             var overlap:Int = overlaps[perm[i-1]][perm[i]]
107             ans.append(A[perm[i]].substring(overlap))
108         }
109         return ans
110     }
111 }
112 
113 extension String {    
114 // 擷取字串:從index到結束處
115     // - Parameter index: 開始索引
116     // - Returns: 子字串
117     func substring(_ index: Int) -> String {
118         let theIndex = self.index(self.endIndex, offsetBy: index - self.count)
119         return String(self[theIndex..<endIndex])
120     }
121     
122     // 擷取字串:指定索引和字元數
123     // - begin: 開始擷取處索引
124     // - count: 擷取的字元數量
125     func substring(_ begin:Int,_ count:Int) -> String {
126         let start = self.index(self.startIndex, offsetBy: max(0, begin))
127         let end = self.index(self.startIndex, offsetBy:  min(self.count, begin + count))
128         return String(self[start..<end]) 
129     }
130 }