leetcode -- Minimum Window Substring -- 重点,应该会考

来源:互联网 发布:手机测甲醛软件 编辑:程序博客网 时间:2024/04/28 01:15

https://leetcode.com/problems/minimum-window-substring/

思路:
与Minimum Subarray Sum题目很像,http://blog.csdn.net/xyqzki/article/details/50354111
用的trick一样。
解题思路:双指针思想,尾指针不断往后扫,当扫到有一个窗口包含了所有T的字符,然后再收缩头指针,直到不能再收缩为止。最后记录所有可能的情况中窗口最小的。

先找到一个window包括所有T的字母,找到window end, 这个时候只是window包括所有的字母,接下来我们就要收缩window的start,直到这个window依然还包括所有的字母。这个时候的start到end就是一个候选的最佳区间,然后end继续往前走,每走一步,都要试图去收缩start,start到end区间会一直包括所有T里面的字母,直到end到末尾

结合最终的code(只用count1,不用count2)来分析,在找第一个window的过程中,count1会因为S中某些字母重复而变成负数,例如S = [AAABAAACAB], T = [ABC], 所以在收缩start的时候,只要S[start]对应的count1小于0,那么就count1[S[start]] += 1,因为只要start继续往前,start:end+1区间肯定还有S[start]出现,但是如果S[start]对应的count1等于0,那么就不能继续往前了,因为继续往前的话,S[start]不会再次出现。这样我们就得到了第一个window的start和end。此时count == 0了,并且接下来一直为0。即,end继续往前走,每走一步,都要试图去收缩start,直到end到末尾。

思路很好理解,复习的时候再做一下。code看不太懂

参考:http://www.cnblogs.com/zuoyuan/p/3785421.html
http://randombet.blogspot.hk/2014/09/leetcode-minimum-window-substring-python.html

Ref中的code

可以AC,但是不好理解,其实可以简化code,见下面的note

class Solution(object):    def minWindow(self, S, T):        """        :type s: str        :type t: str        :rtype: str        """        count1={}; count2={}        for char in T:#count1记录T中字母的个数            if char not in count1: count1[char]=1            else: count1[char]+=1        for char in T:#count2只负责记录s中某个字母是否是T中的字母。            if char not in count2: count2[char]=1            else: count2[char]+=1        count=len(T)        start=0; minSize=100000; minStart=0        for end in range(len(S)):            if S[end] in count2:                count1[S[end]]-=1                if count1[S[end]]>=0:                    count-=1            if count==0:                while True:#一直到count1没有负的。                    if S[start] in count2:                        if count1[S[start]]<0:                            count1[S[start]]+=1                        else:#count1对应元素为0.那么start就不能再往前走了,否则这个元素就不包括在start:end的区间内了。count1没有负的.没有多余的T中的元素,即[start: end + 1]这个range就是最小的range之一。                            break                    start+=1                if minSize>end-start+1:                    minSize=end-start+1; minStart=start                    #break        if minSize==100000: return ''        else:            return S[minStart:minStart+minSize]

note1

这里做了个test,发现找到第一个window之后,count == 0,之后count就一直是0,并且是end每往前走一步,都会试图收缩start。下面用flag作为count是否已经被置为0的标记,如果已经被置为0,以后就等价于去掉if count == 0这个条件。

class Solution(object):    def minWindow(self, S, T):        """        :type s: str        :type t: str        :rtype: str        """        count1={}; count2={}        for char in T:#count1记录T中字母的个数            if char not in count1: count1[char]=1            else: count1[char]+=1        for char in T:#count2只负责记录s中某个字母是否是T中的字母。            if char not in count2: count2[char]=1            else: count2[char]+=1        count=len(T)        start=0; minSize=100000; minStart=0        flag = False        for end in range(len(S)):            if S[end] in count2:                count1[S[end]]-=1                if count1[S[end]]>=0:                    count-=1            if not flag:                if count==0:                    while True:#一直到count1没有负的。                        if S[start] in count2:                            if count1[S[start]]<0:                                count1[S[start]]+=1                            else:#count1对应元素为0.那么start就不能再往前走了,否则这个元素就不包括在start:end的区间内了。count1没有负的.没有多余的T中的元素,即[start: end + 1]这个range就是最小的range之一。                                break                        start+=1                    if minSize>end-start+1:                        minSize=end-start+1; minStart=start                    flag = True            else:                while True:#一直到count1没有负的。                    if S[start] in count2:                        if count1[S[start]]<0:                            count1[S[start]]+=1                        else:#count1对应元素为0.那么start就不能再往前走了,否则这个元素就不包括在start:end的区间内了。count1没有负的.没有多余的T中的元素,即[start: end + 1]这个range就是最小的range之一。                            break                    start+=1                if minSize>end-start+1:                    minSize=end-start+1; minStart=start        if minSize==100000: return ''        else:            return S[minStart:minStart+minSize]

note2,最终code

这里还发现count2其实就只是记录s中的某个字母是否是T中的字母。这里其实只需要count1。

class Solution(object):    def minWindow(self, S, T):        """        :type s: str        :type t: str        :rtype: str        """        count1={}        for char in T:#count1记录T中字母的个数            if char not in count1: count1[char]=1            else: count1[char]+=1        count=len(T)        start=0; minSize=100000; minStart=0        for end in range(len(S)):            if S[end] in count1:                count1[S[end]]-=1                if count1[S[end]]>=0:                    count-=1            if count==0:#找到了第一个window的end                while True:#一直到S[start]对应的count1是0,即没有重复过。就找到了window的start                    if S[start] in count1:                        if count1[S[start]]<0:#说明这个字母重复过,start继续往前的走的话,还有这个字母在后头                            count1[S[start]]+=1                        else:#count1对应元素为0.那么start就不能再往前走了,否则这个元素就不包括在start:end的区间内了。count1没有负的.没有多余的T中的元素,即[start: end + 1]这个range就是最小的range之一。                            break                    start+=1                if minSize>end-start+1:                    minSize=end-start+1; minStart=start        if minSize==100000: return ''        else:            return S[minStart:minStart+minSize]

自己重写code

有bug的code

class Solution(object):    def minWindow(self, s, t):        """        :type s: str        :type t: str        :rtype: str        """        count1 = {}        for x in t:            if x in count1:                count1[x] += 1            else:                count1[x] = 1        count = len(count1)        i, j = 0, 0        minwin = len(s)        min_i, min_j = len(s) - 1, 0        while i < len(s):            if s[i] in count1:                count1[s[i]] -= 1                if count1[s[i]] == 0:                    count -= 1            if count == 0:                while j <= i:                    if s[j] in count1:                        if count1[s[j]] < 0:                            count1[s[j]] += 1                        if count1[s[j]] == 0:#这里要改成elif                            break                    j += 1                if i - j + 1 < minwin:                    minwin = i - j + 1                    min_i = i                    min_j = j            i += 1        if count == 0:            return s[min_j: min_i + 1]        else:            return ''

通过的code

class Solution(object):    def minWindow(self, s, t):        """        :type s: str        :type t: str        :rtype: str        """        count1 = {}        for x in t:            if x in count1:                count1[x] += 1            else:                count1[x] = 1        count = len(count1)        i, j = 0, 0        minwin = len(s)        min_i, min_j = len(s) - 1, 0        while i < len(s):            if s[i] in count1:                count1[s[i]] -= 1                if count1[s[i]] == 0:#这里可以是==0, count = len(count1). 或者跟ref一样                    count -= 1            if count == 0:                while j <= i:#这里有等号跟没等号效果一样。                    if s[j] in count1:                        if count1[s[j]] < 0:                            count1[s[j]] += 1                        elif count1[s[j]] == 0:                            #这里注意一定要是elif而不能是if,否则上面的if如果成立,可能可以又进入这一个if                            break                    j += 1                if i - j + 1 < minwin:                    minwin = i - j + 1                    min_i = i                    min_j = j            i += 1        if count == 0:            return s[min_j: min_i + 1]        else:            return ''
0 0
原创粉丝点击