有模板的题!https://leetcode.com/problems/minimum-window-substring/discuss/26808/Here-is-a-10-line-template-that-can-solve-most-'substring'-problems
class Solution(object):
def minWindow(self, s, t):
"""
:type s: str
:type t: str
:rtype: str
"""
target_map = collections.Counter(t)
count = len(t)
begin = end = head = 0
dis = sys.maxsize
while end < len(s):
if target_map[s[end]] > 0:
count -= 1
target_map[s[end]] -= 1 # aa
end += 1
# When we found a valid window, move start to find smaller window.
while count == 0:
if (end - begin) < dis:
dis = end - begin
head = begin
target_map[s[begin]] += 1 # aa
# When char exists in target, increase counter. 如果不是在t里面的,上面加回来最多回到0
if target_map[s[begin]] > 0:
count += 1
begin += 1
return "" if dis == sys.maxsize else s[head:head + dis]
定义dp[i][j]表示S的前缀S[0,i]中的起始索引k,使得T[0,j]是S[k,i]的子串。这样如果S[i] == T[0],则dp[i][0] = i,否则dp[i][0] = -1。而递推公式为:如果S[i] == T[j],那么dp[i][j] = max(dp[k][j-1]), 0 <= k < i。否则dp[i][j] = -1。而我们的目标则是找到min(i - dp[i][n-1]),其中n是T的长度。
class Solution(object):
def minWindow(self, S, T):
s, t = len(S), len(T)
dp = [[-1]*(t) for _ in xrange(s)]
# if S[i] == T[0] dp[i][0] = i
for i in xrange(s):
if S[i] == T[0]:
dp[i][0] = i
for j in xrange(1, t):
k = -1
for i in xrange(0, s):
# if S[i] == T[j], dp[i][j] = max(dp[k][j-1]) where 0<= k < i
if k != -1 and S[i] == T[j]:
dp[i][j] = k
if dp[i][j-1] != -1:
k = dp[i][j-1]
length = float('inf')
startIdx = -1
for i in xrange(s):
if dp[i][t-1] != -1 and i - dp[i][t-1] + 1 < length :
length = i - dp[i][t-1] + 1
startIdx = dp[i][t-1]
return S[startIdx: startIdx+length] if length != float('inf') else ""
two point beat 100%的方法:
第一个for 先保证T 一定在S里面,第二个for循环就是找最rightmost的T[0]
class Solution:
def minWindow(self, S, T):
res = ""
start = -1
while True:
first = start + 1
for c in T:
start = S.find(c, start + 1)
if start == -1:
return res
start = end = start + 1
for c in reversed(T):
start = S.rfind(c, first, start)
if res == "" or len(res) > end - start:
res = S[start:end]
模板题
class Solution(object):
def lengthOfLongestSubstringTwoDistinct(self, s):
"""
:type s: str
:rtype: int
"""
count = begin = end = dis = 0
window = collections.defaultdict(int)
while end < len(s):
if window[s[end]] == 0:
count += 1 # 有几个不同的字母在window里面了
window[s[end]] += 1 # 把右边字母加到window
end += 1
while count > 2: # 滑动窗口让count == 2
window[s[begin]] -= 1 # 减掉左边的字母
if window[s[begin]] == 0:
count -= 1
begin += 1
dis = max(dis, end-begin)
return dis
最长有效子串的模板题
class Solution(object):
def lengthOfLongestSubstringKDistinct(self, s, k):
"""
:type s: str
:type k: int
:rtype: int
"""
begin = end = dis = count = 0
window_map = collections.defaultdict(int)
while end < len(s):
if window_map[s[end]] == 0:
count += 1
window_map[s[end]] += 1
end += 1
while count > k:
window_map[s[begin]] -= 1
if window_map[s[begin]] == 0:
count -= 1
begin += 1
dis = max(dis, end-begin)
return dis
思路:没想到是分治法之前,一直做不出来。看到可以用分治法后就很容易。
要找s[i,j]的最大子串,先统计频数,然后遍历一遍频数,找出第一个频数小于k且大于0的字符,然后找出这个字符的位置,接下来的分析很重要,这个字符一定不能出现在任何的子串中,因为i,j是整个的子串,在ij里面频数都没有达到k,那么在ij的任何子串中,这个字符也不可能达到频数k。所以不能有这个字符,那么就在这个位置做一个分治,返回前半部分和后半部分的最大值。
class Solution(object):
def longestSubstring(self, s, k):
"""
:type s: str
:type k: int
:rtype: int
"""
return self.divide(0, len(s), s, k)
def divide(self, start, end, s, k):
if end > len(s) or end <= 0:
return 0
dic = collections.defaultdict(int)
check = set()
for i in xrange(start, end):
dic[s[i]] += 1
for i in xrange(start, end):
if dic[s[i]] < k:
check.add(i)
break
if not check:
return end - start
else:
ids = check.pop()
return max(self.divide(start, ids, s, k), self.divide(ids + 1, end, s, k))