Substring with Concatenation of All Words 滑动窗口方法 串联所有单词

# *-  coding:utf-8  -*
'''
这道题感觉难度不小,想了好长时间,没有找到最优解法,看到大神们用一种
滑动窗口方法,确实经典。
滑动窗口思路:
    一个窗口长度是恒定的(与一个单词长度相等),滑动一次窗口的长度,查看目前
    窗口组成的word是否在words中,并要保证word只出现一次,记录状态;如果word满足条件,
    就继续向右移动窗口得到新的word重复上述过程,当所有的word在words中连续找到时,记录
    位置;如果word不在words中,清除记录的状态,窗口
    继续移动。当遍历到s结尾处时,则从s[i]出重新开始上述过程(i<窗口长度)
具体实现:
    字符串s的长度为s_len,每个单词的长度为w_len,(滑动窗口每次移动w_len)那么遍历顺序
    为 0,w_len,2*w_len,....n*w_len (s_len-w_len<=n*w_len<=s_len),第二次遍历的顺序每个
    点向右一定一个字符即:1,w_len+1,2*w_len+1,....,n*w_len+1(s_len-w_len<=n*w_len+1<=s_len),
    一次类推,进行上述w_len次,把s_len中每个字符作为滑动窗口的起始位置都遍历到了。
    采用一个dict或者hash表(如dict1)来存储words中每个word出现的次数,count记录多少个单词出现了,
    采用一个dict或者hash表(shift_w)来存储s中连续区域内每个word出现的次数;word在dict1中,就把
    word加入到shitf_w中,每出现一次计数值加1,count++;当shift_w[word]>dict1[word]时,即单词重复出现啦,
    此时删除最先存入shift_w中的word使其计数值减一,并且count--(为了减少不必要的计算,例如:words中的word
    个数w_counts大于4,w0,w1,w2,w3,w0;当word=w0时,发现shift_w[w0]=2 而dict1[w0]=1,则要删除最左边的w0,
    即第一个word,此时shift_w[w0]=dict1[w0]继续移动窗口即可,因为w1,w2,w3,w0没必要重复计算;
    如果word在s中出现的顺序为: w1,w2,w3,w0,w0 ,则先删除w1,w2,w3,w0后继续移动窗口
    ),重复上述过程,直到满足shift_w[word]<=dict1[word]时继续移动滑动窗口;当count=w_counts时,
    存储窗口开始移动的坐标,并继续上述步骤......

'''
'''
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.
For example, given:
s: "barfoothefoobarman"
words: ["foo", "bar"]

You should return the indices: [0,9].
'''
class Solution(object): 
    def findSubstring(self,s,words):
        dict1={}
        res=[]
        w_len=len(words[0])
        for w in words:
            if w in dict1:
                dict1[w]+=1
            else:
                dict1[w]=1
        for w_pos in range(0,w_len):
            shift_w={}
            w_count=0
            for i in range(w_pos,len(s),w_len):
                word=s[i:i+w_len]
                if word in dict1:
                    if word in shift_w:
                        shift_w[word]+=1
                    else:
                        shift_w[word]=1
                    w_count+=1
                    while dict1[word] < shift_w[word]:
                        rmPos=i - w_len*(w_count-1)
                        rmWord=s[rmPos:rmPos+w_len]
                        print i ,rmWord
                        shift_w[rmWord]-=1
                        w_count-=1
                else:
                    shift_w.clear()
                    w_count=0
                if w_count == len(words):
                    res.append(i - w_len * (w_count-1))
        return res

my=Solution()
s='barfooriitheriifooriibarman'
words=['foo','bar','rii']
print my.findSubstring(s,words)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值