30. 串联所有单词的子串(Swift版)

一、题目

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

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

示例 1:

输入:
  s = "barfoothefoobarman",
  words = ["foo","bar"]
输出:[0,9]

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

示例 2:

输入:
  s = "wordgoodgoodgoodbestword",
  words = ["word","good","best","word"]
输出:[]

二、解题

将字符串(s)分成单词长度(wordLength)种分割方式。
例如示例1:

s="barfoothefoobarman"; words = ["foo","bar"]; wordLength=3;
m1=["foo":1,"bar":1];
组合1:["bar","foo","the","foo","bar","man"]
组合2:["b","arf","oot","hef","oob","arm","an"]
组合3:["ba","rfo","oth","efo","oba","rma","n"]

之后分别处理这三种情况。针对组合的处理见代码实现注释。
时间复杂度为O(m)。n为s的长度,m为words.count。
有两个for循环,第一个for循环为m,第二个for循环为n/m,所以和起来复杂度为O(n)。

三、代码实现

    class Solution {
        func findSubstring(_ s: String, _ words: [String]) -> [Int] {
            if s.isEmpty || words.isEmpty {
                return []
            }
            let wordLength = words[0].count
            var resultARR = [Int]()
            
            
            var m1 = [String: Int]()
            // 将words存入m1中,key为word,value为word在words出现的个数
            for word in words {
                if m1[word] != nil {
                    m1[word]! += 1
                }else {
                    m1[word] = 1
                }
            }
            
            // 遍历wordLength的原因是s的组合方式有wordLength中
            // s="12345678"  wordLength=3
            // 组合一 "123", "456", "78"
            // 组合二 "1", "234", "567", "8"
            // 组合三 "12", "345", "678"
            for i in 0..<wordLength {
                var left = i
                // 记录匹配到的word的总数
                var count = 0
                // 记录匹配到的word各自的数量
                var m2 = [String : Int]()
                // 以i为起点,wordLength为步长,s.count-wordLength+1为终点,遍历
                for j in stride(from: i,to: s.count - wordLength + 1, by: wordLength) {
                    // 取出单词t
                    let t = subString(s, j, wordLength)
                    // 判断t是否在m1中
                    if m1.keys.contains(t) {
                        // t存在在m1中,使用m2记录数量
                        if m2[t] != nil {
                            m2[t]! += 1
                        }else {
                            m2[t] = 1
                        }
                        // 如果m2中t的数量小于等于m1中t的数量说明匹配正确
                        if m2[t]! <= m1[t]! {
                            count += 1
                        }else {// 反之,说明匹配多了,left不符合要求,需要清除之前不符合条件的word
                            while(m2[t]! > m1[t]!) {
                                // 从第left开始往后清理
                                let t1 = subString(s, left, wordLength)
                                m2[t1]! -= 1
                                // 这里的判断是为了区分word重复的情况,当word重复时m2[t1]! == m1[t1]!时,不需要count-1
                                if m2[t1]! < m1[t1]! {
                                    count -= 1
                                }
                                left += wordLength
                            }
                        }
                        // 当count == words.count说明left符合条件,将left添加到最后结果中,并将left向后移动
                        if count == words.count {
                            resultARR.append(left)
                            m2[subString(s, left, wordLength)]! -= 1
                            count -= 1
                            left += wordLength
                        }
                    }else {// 没有找到t,说明匹配中断,需重新处理,并将left向后移动
                        m2.removeAll()
                        count = 0
                        left = j + wordLength
                    }
                }
            }
            return resultARR
        }
        
        func subString(_ s: String, _ loc : Int, _ len : Int) -> String {
            return (s as NSString).substring(with: NSRange(location: loc, length: len))
        }
        
    }

Demo地址:github

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容