包含K个不同字符的最长子串-滑动窗口法-Python2.7

  • 题目描述:
    给定一个字符串和一个正数k,寻找一个包含k个不同字符的最长子串。如果k大于字符串中所有不同字符的个数,就返回整个字符串。
  • 输入描述:
    正数k
    字符串s
  • 输出描述:
    字符串

  • 样例输入:
    k = 2, s = ‘abcbdbdbbdcdabd’
    k = 3, s = ‘abcbdbdbbdcdabd’
    k = 5, s = ‘abcbdbdbbdcdabd’

  • 样例输出:
    k = 2 时,输出 ‘bdbdbbd’
    k = 3 时,输出 ‘bcbdbdbbdcd’
    k = 5 时,输出 ‘abcbdbdbbdcdabd’
  • 思路:
    滑动窗口法。
    滑动窗口法描述:滑动窗口法用一个窗口去满足问题的约束条件。一旦违反约束条件,窗口就会变得不稳定,为了消除这种不稳定,重新满足约束条件,我们需要通过增加或减小窗口的大小。
    在这个问题中,遍历字符串,如果窗口中不同字符个数小于k,则将字符加入到窗口中。如果不同字符的个数大于k,则从最左边的字符开始删除,直到窗口中不同字符的个数等于k。我们反复进行这种改变窗口大小的操作,直到遍历完整个字符串。在这个过程中,如果窗口大小改变,我们就更新最大窗口值。
    Python2.7实现
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/9/16 14:03
# @Author  : Qiankun Wang
# @File    : LongestSubstringK.py
# Function: Find the longest substring fo given string containing k distinct characters using sliding window
# Reference: http://www.techiedelight.com/find-longest-substring-containing-k-distinct-characters/
def LongestSubstringK(s,k):
    begin = 0 # 存储子串的起点
    end = 0 #存储子串的终点
    window = set()
    freq = dict(zip(s,[0]*len(s))) #字符出现的频率
    low = 0 # 窗口的左边界
    # 遍历字符串,将每个字符加入到窗口中,并更新该字符对应的出现频率。
    for high in range(len(s)): # high为窗口的右边界
        window.add(s[high])
        freq[s[high]] += 1
        # 一旦约束条件不满足:即窗口中包含的不同字符的个数大于指定的k,则从左侧开始缩减窗口的大小。
        while len(window) > k:
            # 如果字符只出现一次,我们把该字符从窗口中去除,同时将其对应的频率减一。
            if freq[s[low]] -1 == 0:
                window.remove(s[low])
                freq[s[low]] -= 1
            low += 1 # 缩减窗口的大小
        # 更新窗口的大小(如果条件满足的话)
        if end - begin < high - low:
            end = high
            begin = low
    # 返回满足条件的最长子串
    return s[begin:end+1]
if __name__ == "__main__":
    s = 'abcbdbdbbdcdabd'
    k = 2
    print LongestSubstringK(s,k)

你可能感兴趣的:(算法,滑动窗口,Python)