最左侧冗余覆盖子串

题目描述

给定两个字符串s1和s2和正整数K, 其中s1长度为n1, s2长度为n2, 在s2中选一个子串, 满足:

  • 该子串长度为 n1+k
  • 该子串中包含s1中全部字母
  • 该子串每个字母出现次数不小于s1中对应的字母

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

输入描述

输入三行, 第一行为s1, 第二行为s2, 第三行为k, s1和s2只包含小写字母.

备注:

  • 0 ≤ len(s1) ≤ 1000000
  • 0 ≤ len(s2) ≤ 20000000
  • 0 ≤ k ≤ 1000

输出描述

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

示例1

输入:

ab
aabcd
1

输出:

0

说明: 子串aab和abc符合要求, 由于aab在abc的左侧, 因此输出aab的下标 0.

示例2

输入:

abc
dfs
10

输出:

-1

题解

Python

import string

def solution():
    # 读取输入
    s1 = input()
    s2 = input()
    k = int(input())
    assert 0 < k

    # 统计s1中各个字母出现的次数
    s1_chars = dict((char, 0) for char in string.ascii_lowercase)
    for char in s1:
        s1_chars[char] += 1

    # 滑动窗口内各个字母出现的次数
    window_chars = dict((char, 0) for char in string.ascii_lowercase)
    left = 0
    right = 0
    s1_chars_left = len(s1)

    while right < len(s2):
        # 更新窗口内各个字母的次数
        right_char = s2[right]
        window_chars[right_char] += 1

        if window_chars[right_char] <= s1_chars[right_char]:
            s1_chars_left -= 1

        # 如果窗口太大, 将窗口左侧向右移
        if right - left + 1 > len(s1) + k:
            left_char = s2[left]
            if window_chars[left_char] <= s1_chars[left_char]:
                s1_chars_left += 1

            # 将左侧字符从窗口字母计数中移除
            window_chars[left_char] -= 1
            left += 1

        # 如果 s1 中没有剩下的字符待检查, 就说明找到了子串
        if s1_chars_left == 0:
            return left

        # 将窗口右侧向右移
        right += 1

    return -1

def main():
    ans = solution()
    print(ans)

if __name__ == "__main__":
    main()