为有牺牲多壮志,敢教日月换新天。

[Swift]LeetCode30. 与所有单词相关联的字串 | Substring with Concatenation of All Words

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/9897592.html 
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

热烈欢迎,请直接点击!!!

进入博主App Store主页,下载使用各个作品!!!

注:博主将坚持每月上线一个新app!!!

You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening characters.

Example 1:

Input:
  s = "barfoothefoobarman",
  words = ["foo","bar"]
Output: [0,9]
Explanation: Substrings starting at index 0 and 9 are "barfoor" and "foobar" respectively.
The output order does not matter, returning [9,0] is fine too.

Example 2:

Input:
  s = "wordgoodstudentgoodword",
  words = ["word","student"]
Output: []

给定一个字符串 s 和一些长度相同的单词 words。在 s 中找出可以恰好串联 words 中所有单词的子串的起始位置。

注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。

示例 1:

输入:
  s = "barfoothefoobarman",
  words = ["foo","bar"]
输出: [0,9]
解释: 从索引 0 和 9 开始的子串分别是 "barfoor" 和 "foobar" 。
输出的顺序不重要, [9,0] 也是有效答案。

示例 2:

输入:
  s = "wordgoodstudentgoodword",
  words = ["word","student"]
输出: []

304ms
 1 class Solution {
 2     func findSubstring(_ s: String, _ words: [String]) -> [Int] {
 3         guard !words.isEmpty else {
 4             return []
 5         }
 6         guard !s.isEmpty else {
 7             return words.contains("") ? [0] : []
 8         }
 9         
10         let string = Array(s)
11         let wordLength = words[0].count
12         let totalWordLength = words.count * wordLength
13         
14         guard totalWordLength <= string.count else {
15             return []
16         }
17         
18         let originalWordToCount = words.reduce(into: [:], { $0[$1, default:0] += 1 })
19         
20         var startingIndices: [Int] = []
21         
22         for i in 0..<wordLength {
23             
24             var startIndex = i
25             var wordToCount = originalWordToCount
26             
27             for j in stride(from: i, to: string.count-wordLength+1, by: wordLength) {
28                 
29                 let word = String(string[j..<(j+wordLength)])
30                 
31                 if let originalCount = originalWordToCount[word] {
32                     
33                     while wordToCount[word] == nil {
34                         let startWord = String(string[startIndex..<(startIndex+wordLength)])
35                         wordToCount[startWord, default: 0] += 1
36                         startIndex += wordLength
37                     }
38                     
39                     if let currentCount = wordToCount[word] {
40                         if currentCount == 1 {
41                             wordToCount[word] = nil 
42                         } else {
43                             wordToCount[word] = currentCount - 1
44                         }
45                     }
46                     
47                     if wordToCount.isEmpty {
48                         startingIndices.append(startIndex)
49                         
50                          let startWord = String(string[startIndex..<(startIndex+wordLength)])
51                         wordToCount[startWord, default: 0] += 1
52                         startIndex += wordLength
53                     }
54                     
55                 } else {
56                     // reset 
57                     startIndex = j+wordLength
58                     wordToCount = originalWordToCount
59                 }
60             }
61         }
62         
63         return startingIndices
64     }
65 }

312ms

 1 class Solution {
 2     func findSubstring(_ s: String, _ words: [String]) -> [Int] {
 3         guard !words.isEmpty else {
 4             return []
 5         }
 6         guard !s.isEmpty else {
 7             return words.contains("") ? [0] : []
 8         }
 9         
10         let string = Array(s)
11         
12         let wordLength = words[0].count
13         let totalWordLength = words.count * wordLength
14         
15         guard string.count >= totalWordLength else {
16             return []
17         }
18         
19         let originalWordToCount = words.reduce(into: [:], { $0[$1, default: 0] += 1 })
20         
21         var startingIndices: [Int] = []
22         
23         for i in 0..<wordLength {
24 
25             var startIndex = i
26             var wordToCount: [String:Int] = [:]
27             var wordCount = 0
28             
29             for j in stride(from: i, to: string.count - wordLength + 1, by: wordLength) {
30                 
31                 let word = String(string[j..<(j+wordLength)])
32                 
33                 if let originalCount = originalWordToCount[word] {
34                     
35                     wordToCount[word, default: 0] += 1
36                     wordCount += 1
37                     
38                     while let count = wordToCount[word], count > originalCount {
39                         let startWord = String(string[startIndex..<(startIndex+wordLength)])
40                         wordCount -= 1
41                         wordToCount[startWord, default: 1] -= 1
42                         startIndex += wordLength
43                     }
44                     
45                     if wordCount == words.count {
46                         startingIndices.append(startIndex)
47                         
48                         let startWord = String(string[startIndex..<(startIndex+wordLength)])
49                         wordCount -= 1
50                         wordToCount[startWord, default: 1] -= 1
51                         startIndex += wordLength
52                     }
53                     
54                 } else {
55                     // reset
56                     startIndex = j+wordLength
57                     wordToCount = [:]
58                     wordCount = 0
59                 }
60             }
61         }
62         
63         return startingIndices
64     }
65 }

424ms

 1 class Solution {
 2     func findSubstring(_ s: String, _ words: [String]) -> [Int] {
 3         
 4         guard !words.isEmpty else {
 5             return []
 6         }
 7         guard !s.isEmpty else {
 8             return words.contains(s) ? [0] : []
 9         }
10         
11         let string = Array(s)
12         let wordLength = words[0].count
13         let totalWordLength = wordLength * words.count
14         
15         guard totalWordLength <= string.count else {
16             return []
17         }
18         
19         let originalWordToCount = words.reduce(into: [:], { $0[$1, default: 0] += 1 })
20         
21         var startingIndices: [Int] = []
22         
23         for i in 0..<wordLength {
24             
25             var startIndex = i
26             var currentWordToCount = originalWordToCount
27             
28             for j in stride(from: i, to: string.count-wordLength+1, by: wordLength) {
29                 
30                 let word = String(string[j..<(j+wordLength)])
31                 
32                 if let originalCount = originalWordToCount[word] {
33                     
34                     while currentWordToCount[word] == nil {
35                         let startWord = String(string[startIndex..<(startIndex+wordLength)])
36                         startIndex += wordLength
37                         currentWordToCount[startWord, default: 0] += 1
38                     }
39                     
40                     if let currentCount = currentWordToCount[word] {
41                         if currentCount == 1 {
42                             currentWordToCount[word] = nil
43                         } else {
44                             currentWordToCount[word] = currentCount-1
45                         }
46                     }
47                     
48                     if currentWordToCount.isEmpty {
49                         startingIndices.append(startIndex)
50                         
51                         // get a new combination
52                         let startWord = String(string[startIndex..<(startIndex+wordLength)])
53                         startIndex += wordLength
54                         currentWordToCount[startWord] = 1
55                     }
56                     
57                 } else {
58                     // reset
59                     startIndex = j+wordLength
60                     currentWordToCount = originalWordToCount
61                 }
62             }
63         }
64         
65         return startingIndices
66     }
67 }

1128ms

 1 class Solution {
 2     func findSubstring(_ s: String, _ words: [String]) -> [Int] {
 3         if words.isEmpty {
 4             return []
 5         }
 6         let wordLen = words[0].count
 7         let substrLen = words.count * wordLen
 8         
 9         if s.count <  substrLen {
10             return []
11         }
12 
13         var answer = [Int]()
14         answer.reserveCapacity(s.count)
15 
16         var dict = [String:Int]()
17         for w in words {
18             var count = 1
19             if let v = dict[w] {
20                 count = count + v
21             }
22             dict[w] = count
23         }
24         
25         var i = s.startIndex
26         let end = s.index(s.endIndex, offsetBy: -substrLen)
27         while i <= end {
28             if isSubstring(s[i..<s.index(i, offsetBy:substrLen)], dict, wordLen) {
29                 answer.append(s.distance(from: s.startIndex, to: i))
30             }
31             i = s.index(after: i)
32         }
33         return answer
34     }
35     
36     func isSubstring(_ s: Substring, _ words: [String:Int], _ wordLen: Int) -> Bool {
37         var d = words
38         var substr = s
39         while !substr.isEmpty {
40             let w = String(substr[substr.startIndex..<substr.index(substr.startIndex, offsetBy: wordLen)])
41             if let c = d[w], c > 0 {
42                 d[w] = c - 1
43             } else {
44                 return false
45             }
46             substr = substr[substr.index(substr.startIndex, offsetBy: wordLen)...]
47         }
48         return true
49     }
50 }

1852ms

 1 class Solution {
 2     func findSubstring(_ s: String, _ words: [String]) -> [Int] {
 3         if s == nil || words.count == 0 {
 4             return []
 5         }
 6         var result: [Int] = []
 7         var dict1: [String: Int] = [String: Int]()
 8         var dict2: [String: Int] = [String: Int]()
 9         let stringLength: Int = s.count
10         let wordsListSize: Int = words.count
11         let wordLength: Int = words[0].count
12         for i in 0 ..< wordsListSize {
13             if dict1[words[i]] == nil {
14                 dict1[words[i]] = 1
15             } else {
16                 dict1[words[i]]! += 1
17             }
18         }
19         var s1: String
20         var s2: String
21         var counter1: Int
22         var counter2: Int
23         for i in 0 ..< wordLength {
24             counter1 = 0
25             counter2 = i
26             var j = i;
27             while j < stringLength {
28                 s1 = s[j..<j+wordLength]
29                 if dict1[s1] == nil {
30                     dict2.removeAll(keepingCapacity: false)
31                     counter1 = 0
32                     counter2 = j + wordLength
33                 } else if dict2[s1] == nil || dict2[s1]! < dict1[s1]! {
34                     if dict2[s1] == nil {
35                         dict2[s1] = 1
36                     } else {
37                         dict2[s1]! += 1
38                     }
39                     counter1 += 1
40                 } else {
41                     s2 = s[counter2..<counter2+wordLength]
42                     while s2 != s1 {
43                         dict2[s2]! -= 1
44                         counter1 -= 1
45                         counter2 += wordLength
46                         s2 = s[counter2..<counter2+wordLength]
47                     }
48                     counter2 += wordLength
49                 }
50                 if counter1 == wordsListSize {
51                     result.append(counter2)
52                     s2 = s[counter2..<counter2+wordLength]
53                     dict2[s2]! -= 1
54                     counter1 -= 1
55                     counter2 += wordLength
56                 }
57                 j += wordLength
58             }
59             dict2.removeAll(keepingCapacity: false)
60         }
61         return result
62     }
63 }
64 
65 private extension String {
66     subscript (range: Range<Int>) -> String {
67         guard let localEndIndex = self.index(self.startIndex, offsetBy: range.upperBound, limitedBy: self.endIndex) else {
68             return String(self[self.index(self.startIndex, offsetBy: range.lowerBound)..<self.endIndex])
69         }
70         return String(self[self.index(self.startIndex, offsetBy: range.lowerBound)..<localEndIndex])
71     }
72 }

3192ms

 1 class Solution {
 2     func findSubstring(_ s: String, _ words: [String]) -> [Int] {
 3         if words.count == 0 { return [] }
 4         let len = words[0].count
 5         
 6         let s = Array(s.characters)
 7         let concatLen = len * words.count
 8         
 9         if s.count < concatLen { return [] }
10         
11         // Map word to count
12         var dict = [String: Int]()
13         for i in 0..<words.count {
14             let count = (dict[words[i]] ?? 0) + 1
15             dict[words[i]] = count
16         }
17         
18         var res = [Int]()
19         for i in 0..<(s.count-words.count*len+1) {
20             var track = [String: Int]()
21             var ok = true
22             let startSequence = (0..<words.count).map { i + $0 * len }
23             for start in startSequence {
24                 let substring = String(s[start..<start+len])
25                 let count = (track[substring] ?? 0) + 1
26                 if count > (dict[substring] ?? 0) {
27                     ok = false
28                     break
29                 }
30                 track[substring] = count
31             }
32             
33             if ok {
34                 res.append(i)
35             }
36         }
37         
38         return res
39     }
40 }

3480ms

 1 class Solution {
 2     func findSubstring(_ s: String, _ words: [String]) -> [Int] {
 3         guard s.count > 0 && words.count > 0 else {
 4         return []
 5     }
 6     
 7     var counts = [String: Int]()
 8     words.forEach { word in
 9         counts[word, default: 0] += 1
10     }
11     
12     var indices = [Int]()
13     let ss = s.utf8CString
14     let n = s.count
15     let wc = words.count
16     let len = words.first!.count
17     for i in 0..<(n - wc * len + 1) {
18         var seen = [String: Int]()
19         var j = 0
20         while j < wc {
21             let cs = Array(ss[(i + j * len)..<(i + (j + 1) * len)]) + [0]
22             let word = String(cString: cs)
23             if words.contains(word) {
24                 seen[word, default: 0] += 1
25                 if seen[word]! > counts[word]! {
26                     break
27                 }
28             } else {
29                 break
30             }
31             j += 1
32         }
33         
34         if j == wc {
35             indices.append(i)
36         }
37     }
38     return indices
39     }
40 }

3556ms

 1  class Solution {
 2     func findSubstring(_ s: String, _ words: [String]) -> [Int] {
 3         var results:[Int] = []
 4         if s == nil || s.isEmpty || words == nil || words.isEmpty {return results}
 5         var h:[String: Int] = [String: Int]()
 6         for word in words
 7         {
 8             if h[word] == nil
 9             {
10                 h[word] = 1
11             }
12             else
13             {
14                 h[word] = h[word]! + 1
15             }
16         }
17         var len:Int = words[0].count
18         for offset in 0..<len
19         {
20             var f:[String: Int] = [String: Int]()
21             var from:Int = offset
22             var count:Int = 0
23             for i in stride(from: offset,through:s.count - len,by: len)
24             {
25                 var word:String = s.subString(i,len)
26                 var hc:Int? = h[word]
27                 if hc == nil
28                 {
29                     from = i + len
30                     count = 0
31                     f = [String: Int]()
32                     continue
33                 }
34                 var fc:Int? = f[word]
35                 if fc == nil
36                 {
37                     fc = 1
38                 }
39                 else
40                 {
41                     fc = fc! + 1
42                 }
43                 f[word] = fc
44                 count += 1
45                 while (fc! > hc!)
46                 {
47                     var fword = s.subString(from,len)
48                     f[fword] = f[fword]! - 1
49                     fc = f[word]!
50                     from += len
51                     count -= 1
52                 }
53                 if count == words.count
54                 {
55                    results.append(from)
56                 }
57             }
58         }
59         return results
60     }
61 }
62 
63 extension String {
64     // 截取字符串:指定区间
65     // - Parameter range: 闭区间
66     // - Returns: 子字符串
67     func subString(_ begin:Int,_ count:Int) -> String {
68         let start = self.index(self.startIndex, offsetBy: begin)
69         let end = self.index(self.startIndex, offsetBy: begin + count - 1)
70         return String(self[start...end]) 
71     }
72 }

 

posted @ 2018-11-02 17:52  为敢技术  阅读(344)  评论(0编辑  收藏  举报