LeetCode 30. 串联所有单词的子串

题目:


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

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

示例 1:

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

示例 2:

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

思路:

脑子不灵光,可以想出滑动的指针方法, 但是写不出来...

暴力搜索是我最后的倔强~~~~

方法一:

暴力搜索~~~

以words中一个str的长度(题目条件是每个元素长度都相同),进行查找。因为不用考虑顺序,所以只要从s中截取的部分包含在words(因为是匹配该列表,每次都循环都需要该对象,所以用切片来copy复制,找到就可以remove掉,没有就不符合条件跳出,当列表长度为0的时候,index即符合条件。

class Solution(object):
    def findSubstring(self, s, words):
        """
        :type s: str
        :type words: List[str]
        :rtype: List[int]
        """
        if len(words)==0 or len(s)==0:
            return []

        wl=len(words[0])
        ss=[]
        for i in range(len(s)-wl*len(words)+1):
            tw=words[:] #需要用切片深copy匹配串
            k=i
            while len(tw)!=0:
                if s[k:k+wl] in tw: #当等间距长度检索的字符包含在匹配串中 ,就remove
                    tw.remove(s[k:k+wl])
                    k+=wl
                else:
                    break
            if len(tw)==0: #长度为0即为符合条件的index,塞入数组
                ss.append(i)
        
        return ss

方法二:

摘自题解summer_tree ,思路很清晰~我也有想到双指针移动,但是写不出~~苦恼😖

1、首先这个题里, words里的子串长度都相等,则这个题类似76题,可以把words看成一个字符串,里面的每个word 看成一个字母,
2、words=["foo","bar"] 即 words="AB", 则 s="barfoothefoobarman" => "BAXABY",
3、就转换成了 给个字符串s ,模式串t, 求包含模式串字符的子串

class Solution(object):
    def findSubstring(self, s, words):
        """
        :type s: str
        :type words: List[str]
        :rtype: List[int]
        """
       
        import collections
        if not s or not words:
            return []
        
        words_dict = collections.Counter(words)
        one_word_len = len(words[0])
        n = len(s)
        if n < one_word_len:
            return []
        
        window_cnt = 0
        cur_window_dict = collections.Counter()
        ret = []
        for i in range(one_word_len):
            left = right = i 
            cur_window_dict.clear()
            while right + one_word_len <= n:
                #从s中取一个word长度的串
                c = s[right: right + one_word_len]
                right += one_word_len
                #如果没有在模式串中 直接清空map, left 前进到 right位置
                if c not in words_dict:
                    left = right
                    cur_window_dict.clear()
                    window_cnt = 0
                else:
                    cur_window_dict[c] += 1
                    window_cnt += 1

                    #缩小窗口
                    while cur_window_dict[c] > words_dict[c]:
                        d = s[left: left + one_word_len]
                        cur_window_dict[d] -= 1
                        left += one_word_len

                    #直接判断两个counter 是否相等
                    if cur_window_dict == words_dict:
                        ret.append(left)
        return ret 

或者是这样:

出自作者:HardCandy,讲解的也蛮细致的,从最直接的单个字符去搜索,到变成以字符长度,最后到优化过滤不符合条件的case。
很直观的了解这题目的思路~

class Solution(object):
    def findSubstring(self, s, words):
        """
        :type s: str
        :type words: List[str]
        :rtype: List[int]
        """
        if not words:
            return []
        w_len, s_len = len(words[0]), len(s)
        t_len = w_len * len(words)  # 子串的长度

        word_dict = {}  # words的哈希表
        for word in words:
            word_dict[word] = word_dict.get(word, 0) + 1 #统计word中每个字符的次数

        ans = []
        for offset in range(w_len):
            lo, lo_max = offset, s_len - t_len
            while lo <= lo_max:
                tmp_dict = word_dict.copy()
                match = True
                for hi in range(lo + t_len, lo, -w_len):    # 从尾到头搜索单词
                    word = s[hi - w_len: hi]
                    if word not in tmp_dict or tmp_dict.get(word, 0) == 0:
                        match = False
                        break   # 当前单词不符合要求 直接停止这个子串的搜索
                    tmp_dict[word] -= 1
                if match:
                    ans.append(lo)
                lo = hi     # 对lo直接赋值
        return ans
posted @ 2021-02-26 16:46  萧蔷ink  阅读(117)  评论(0编辑  收藏  举报