386. 最多有k个不同字符的最长子字符串

386. 最多有k个不同字符的最长子字符串

中文English

给定字符串S,找到最多有k个不同字符的最长子串T

样例

样例 1:

输入: S = "eceba" 并且 k = 3
输出: 4
解释: T = "eceb"

样例 2:

输入: S = "WORLD" 并且 k = 4
输出: 4
解释: T = "WORL" 或 "ORLD"

挑战

O(n) 时间复杂度

输入测试数据 (每行一个参数)如何理解测试数据?

 第一种写法:(同向型双向指针)

class Solution:
    """
    @param s: A string
    @param k: An integer
    @return: An integer
    """
    def lengthOfLongestSubstringKDistinct(self, s, k):
        # write your code here
        if len(s) <= k: return len(s)
        
        array = []
        l, max_value = len(s), 0
        count = 0 
        j = 0
        
        #主指针,缩小区间,维持区间内都符合条件
        for i in range(l):
            j = i

            #一定要在count <= k里面,直到等于k的时候才可以,不然会出现刚好到k的情况,立马跳出循环。这样的话就不是取到最大长度了,例如j,j,j
            #刚好出现第一个j新字符,就跳出循环,后面就不在append到array里面了
            while count <= k and j < l:#count = k 重要,否则无法更新到最长相同字符串那里
                if s[j] not in array:
                    count += 1 
                array.append(s[j])
                j += 1 

                if (count <= k):
                    max_value = max(j - i, max_value)
            
            #缩小区间
            count = 0 
            array = []

        return max_value

注:lintcode未通过,时间复杂度问题,待优化

优化版本一:通过字典的方式(外面缩减区间,里面增大区间)

class Solution:
    """
    @param s: A string
    @param k: An integer
    @return: An integer
    """
    def lengthOfLongestSubstringKDistinct(self, s, k):
        # write your code here
        if len(s) <= k: return len(s)
        
        counter = {}
        l, max_value = len(s), 0
        j = 0
        
        #主指针,缩小区间,维持区间内都符合条件
        for i in range(l):
            #一定要在count <= k里面,直到等于k的时候才可以,不然会出现刚好到k的情况,立马跳出循环。这样的话就不是取到最大长度了,例如j,j,j
            #刚好出现第一个j新字符,就跳出循环,后面就不在append到array里面了
            while len(counter) <= k and j < l:
                counter[s[j]] = counter.get(s[j], 0) + 1
                j += 1 
                if (len(counter) <= k):
                    max_value = max(j - i, max_value)

            #缩小区间
            counter[s[i]] -= 1 
            if counter[s[i]] == 0:
                del counter[s[i]]
            
        return max_value

优化版本二(外面增大区间,里面缩减区间,一直缩减到符合最长不同字符为k截止,跳出循环)

class Solution:
    """
    同向型双指针
    """
    def lengthOfLongestSubstringKDistinct(self, s, k):
        #维持区间在满足最长不同字符k长度左右
        if not s: return 0 

        counter = {}
        l = len(s)
        max_res = 0
        j = 0

        #增大区间,主指针
        for i in range(l):
            counter[s[i]] = counter.get(s[i], 0) + 1
            
            #缩小区间,维持最长不同字符为k,如果大于k,则开始缩减,注意大于即可,一直到等于便可以跳出循环
            while len(counter) > k and j < l:
                counter[s[j]] -= 1
                if counter[s[j]] == 0:
                    del counter[s[j]]
                
                #可能存在多个相同的,也会一直缩减到不同字符长度k截止
                j += 1
            
            #在这里已经是符合条件的k长度了,所以可以取最大值
            max_res = max(max_res, i - j + 1)
        
        return max_res

 

posted @ 2020-06-25 23:43  风不再来  阅读(359)  评论(0编辑  收藏  举报