leetcode第三十题 —— 串联所有单词的子串

1.题目

原题:

给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。

例子:

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

2.解析

这道题总共有三个解法:暴力求解法、滑动窗口法和双指针法,笔者选择双指针法求解,关于其他两种方法,大家可以自己百度。
双指针法是降低算法复杂度的有效方法,在这道题里思路是:
首先,前提是设置一个字典统计输入单词列表里每一个词出现的顺序,我们称为dict_words,接下来针对输入的字符串进行滑动,用一个新字典统计滑动得到的字符串,我们称为dict_str,用一个变量统计匹配单词的数量,我们称为word_count。接下来是操作重点。
(1)设置初始位置i,因为不同的初始位置会出现不同的字符串划分,出现不同的单词,而且要匹配单词列表里的词不一定第一个字符串就匹配上了,初始位置i设置的循环为(0,单词长度),这样就可以保证各种划分方式都能取到。
(2)设置初始双指针指向同一个位置i,以单词字母数为长度滑动右指针,判断子字符串是不是在待匹配单词表里。
如果不在好说,重置匹配单词计数和字典,重新开始匹配。
如果在,那么首先判断这个字符串在不在dict_str里,如果在就计数+1,不在就赋值1,此时算一个正确匹配。这个时候,还要实时关注匹配到的单词数是不是超过了输入单词列表里的单个单词数,如果超过显然匹配失败了,因此在做一个左滑动,匹配次数减1,保证dict_str里的单词计数小于dict_word里的单词计数。滑动的单位是单个单词长度。
(3)最后关注一下匹配计数wordcount和len(words)相不相等,相等的话算是一个正确的匹配,返回左指针。
整体的思路就是这样了,具体可以结合代码理解一下。

3.python代码

class Solution:
    def findSubstring(self, s, words):
        if len(s) == 0 or len(s) < len(''.join(words)) or not words:
            return []
        dict_words = {}
        dict_str = {}
        n = len(words[0])
        out_num = []
        for word in words:
            if word in dict_words:
                dict_words[word] += 1
            else:
                dict_words[word] = 1
        for i in range(n):
            # 切分方式的不同,注意切分方法的区别
            left = i
            right = i
            dict_str = {}
            word_count = 0
            while right <= len(s) - n:
                right_str = s[right: right+n]
                if right_str in dict_words:
                    if right_str in dict_str:
                        dict_str[right_str] += 1
                    else:
                        dict_str[right_str] = 1
                    word_count += 1
                    right += n
                    print(dict_str)
                    if dict_str[right_str] > dict_words[right_str]:
                        while dict_str[right_str] > dict_words[right_str]:
                            leftstr = s[left: left+n]
                            dict_str[leftstr] -= 1
                            word_count -= 1
                            left += n
                    if word_count == len(words):
                        out_num.append(left)
                else:
                    right += n
                    left = right
                    word_count = 0
                    dict_str = {}
        return out_num

你可能感兴趣的:(leetcode第三十题 —— 串联所有单词的子串)