最左侧冗余覆盖子串

题目描述
给定两个字符串 s1 和 s2 和正整数 k,其中 s1 长度为 n1,s2 长度为 n2。

在 s2 中选一个子串,若满足下面条件,则称 s2 以长度 k 冗余覆盖 s1

该子串长度为 n1 + k

该子串中包含 s1 中全部字母

该子串每个字母出现次数不小于 s1 中对应的字母

给定 s1,s2,k,求最左侧的 s2 以长度 k 冗余覆盖 s1 的子串的首个元素的下标,如果没有返回-1。

举例:

s1 = “ab”

s2 = “aabcd”

k = 1

则子串 “aab” 和 “abc” 均满足此条件,由于 “aab” 在 “abc” 的左侧,“aab” 的第一个元素下部为 0,因此输出 0

输入描述
输入三行,第一行为 s1,第二行为 s2,第三行为 k

s1 和 s2 只包含小写字母
输出描述
最左侧的 s2 以长度 k 冗余覆盖 s1 的子串首个元素下标,如果没有返回 -1。

备注
0 ≤ len(s1) ≤ 1000000
0 ≤ len(s2) ≤ 20000000
0 ≤ k ≤ 1000
用例1
输入
ab
aabcd
1
输出
0
说明
子串aab和abc符合要求,由于aab在abc的左侧,因此输出aab的下标:0

用例2
输入
abc
dfs
10
输出
-1
说明
s2无法覆盖s1,输出 -1

"""
如果只是简单的滑动窗口的话,时间复杂度为O(n^2)
可能因为数量级高而超时,因此需要优化一下
"""
def sliding(S1,S2,K):
    n1 = len(S1)
    n2 = len(S2)
    if n2<n1+K:
        return -1
    #统计一下S1中每个字符出现的次数
    count={}
    for c in S1:
        if count.get(c) is None:
            count[c] = 1
        else:
            count[c]+=1
    #记录S1中字符的总数、
    total = n1
    windows_len = n1+K
    maxI = n2-windows_len  #可以滑动的最大范围
    # 统计 s2 的 0 到windows范围内出现的 s1 中字符的次数
    for j in range(windows_len):
        c = S2[j]
        if count.get(c) is not None:
            if count[c]>0:
                total-=1    #找到了一个字符
            count[c]-=1
        if total==0:
            return 0  #返回起始索引

    # 从左边界 1 开始的滑动窗口,利用差异思想避免重复计算
    for i in range(1,maxI):
        #滑动窗口右移更新窗口
        remove = S2[i-1] #移除的字符
        add    = S2[i+windows_len-1] #加入的字符

        if count.get(remove) is not None:
            if count[remove]>=0:#如果 count[remove] 非负,说明它在有效字符之内
                total+=1
            count[remove]+=1
        if count.get(add) is not None:
            if count[add]>0:
                total-=1
            count[add]-=1
        if total == 0:
            return i
    return -1
if __name__ == '__main__':
    S1 = input()
    S2 = input()
    K = int(input())
    result = sliding(S1,S2,K)
    print(result)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值