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

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值