字符串专题(匹配,子序列)
给定文本text和待匹配字符串pattern,二者皆只包含小写字母,并且不为空。
在text中找出匹配pattern的最短字符串,匹配指按序包含pattern,但不要求pattern连续。
如text为abaacxbcbbbbacc,pattern为cbc,text中满足条件的是abaacxbcbbbbacc下划线部分。
输入为每行两个字符串,前者为模式串s1,后者为待匹配串s2。
输出最短匹配序列起止位置(位置下标从0开始),用空格分隔。若有多个答案,输出起止位置最小的答案;若无满足条件的答案,则起止均为-1。
思路:共进退法
例子是s1=abcabcbc 和 s2=cbc。 i为s1的索引,j为s2的索引。下面演示i,j如何共进退。
现在s1中找出包含s2的第一个区间:cabc,此时索引i=5,j=2。那么这时j已经指向了子串末尾,i也指向了字串末尾(i,j共进)。那怎样获取子区间首尾位置呢?其实现在i就是尾部位置,用k=i记录下来。然后获取头部位置:就是将i往回倒退,同时j也往回倒退,直到j倒退到子串第一个元素,此时i也退到了字串的第一个元素(i,j共退)。此时k-i+1的长度就是包含子串的子区间长度。此时记录首尾位置和子区间长度。现在i位于这个子区间的首元素下一位,j位于s2的头部,又开始了新一轮的查找(共进退)。循环直到i超出s1的长度结束。
有了上面的共进退思想,代码就很好理解了:
def match(s1, s2):
if len(s1)<len(s2):return(-1,-1)
i,j=0,0
l,r,min_l = -1,-1,len(s1)+1 # l,r分别为子区间的首尾位置
while i<len(s1):
if s1[i]==s2[j]: # 如果当前i,j两个指针所指元素一样,
if j==len(s2)-1: # 则判断j是否已经走到了串尾
k = i # 如果是,则此时找到了一个子区间,用k标记尾部
while(j>=0): # i和j共退,来得到头部位置
if s1[i]==s2[j]:
j-=1
i-=1
i+=1 # 得到了头部位置i
temp_min = k-i+1 # 子区间长度就是k-i+1
if temp_min<min_l: # 如果这个子区间长度更小
l,r,min_l = i,k,temp_min # 则更新左右边界和子区间长度
else: # 如果此时两串所指元素一样,但还没有到末尾,则i,j继续向前
i+=1
j+=1
else: # 如果i,j指向元素不一样,则i继续走呀
i+=1
return (l,r)
while True:
try:
s1,s2 = input().split(' ')
l,r = match(s1,s2)
print(l,r)
except:
break

浙公网安备 33010602011771号