LeetCode之串联所有单词的子串(30)

给定一个字符串 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”] 输出:[]

这题的难度是困难。
我第一次做,想到的是暴力解法。即创造一个words的字典,对字符串进行遍历。截取一段分割后存入一个新字典,如果与原字典相同,说明全匹配,添加即可。说起来,不考虑字典花费的时间的话,时间复杂度应该是O(nm)。以下是代码

class Solution:
    def make_list(self,s:str,n:int,word:dict)->bool:
        i=0
        joke={}
        #print(s)
        while(i<len(s)):
            if s[i:i+n] not in word:
                return False
            if s[i:i+n] in joke:
                joke[s[i:i+n]]+=1
            else:
                joke[s[i:i+n]]=1
            i+=n
        return joke==word
    def findSubstring(self, s: str, words: List[str]) -> List[int]:
        if len(words)==0:
            return []
        if not words[0]:
            return [i for i in range(len(s)+1)]
        word={}
        joke=[]
        for i in words:
            if i in word:
                word[i]+=1
            else:
                word[i]=1
        len_of_word=len(words[0])
        for left in range(len(s)):
            right=left+len(words)*len_of_word
            if self.make_list(s[left:right],len_of_word,word):
                joke.append(left)
        return joke

8000多ms,这就太丢脸了,一定有更好的办法。
改进了一下
这个主要就是对字典的使用进行了改进,不必每次从头开始添加,而是每次删去多余的我们不需要的数据。

class Solution:
    def findSubstring(self, s: str, words: List[str]) -> List[int]:
        if len(words)==0:
            return []
        if not words[0]:
            return [i for i in range(len(s)+1)]
        word={}
        ans=[]
        for i in words:
            if i in word:
                word[i]+=1
            else:
                word[i]=1
        lwd=len(words[0])#len_of_word
        lwds=lwd*len(words)#len_of_words
        for i in range(min(lwd,len(s)-lwds+1)):
            left=wp=i#word_position
            test={}
            while(left+lwds<=len(s)):
                w=s[wp:wp+lwd]
                wp+=lwd
                if w in word:
                    if w in test:
                        test[w]+=1
                        while(test[w]>word[w]):
                            test[s[left:left+lwd]]-=1
                            left+=lwd
                    else:
                        test[w]=1
                else:
                    left=wp
                    test.clear()
                if left+lwds==wp:
                    ans.append(left)        
        return ans

再贴一个方法跟我类似但是时间效率比我好的代码吧

执行用时为 64 ms 的范例
class Solution:
	def findSubstring(self, s, words):
		if len(words) == 0:
			return []
		lens = len(s)
		lenw = len(words[0])
		lenws = lenw * len(words)
		if lens < lenws:
			return []
		counter = {}
		for i in range(len(words)):
			if words[i] in counter:
				counter[words[i]] += 1
			else:
				counter[words[i]] = 1
		res = []
		for i in range(min(lenw, lens-lenws + 1)):
			s_pos = word_pos = i
			d = {}
			while s_pos + lenws <= lens:
				# 截取单词
				word = s[word_pos:word_pos + lenw]
				# 移动到下一个单词
				word_pos += lenw
				if word not in counter:
					s_pos = word_pos
					d.clear()
				else:
					if word not in d:
						d[word] = 1
					else:
						d[word] += 1
					while d[word] > counter[word]:
						d[s[s_pos:s_pos + lenw]] -= 1
						s_pos += lenw
					if word_pos - s_pos == lenws:
						res.append(s_pos)
		return res
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值