Skip to content

230826 Longest K unique characters substring

【题意】:在所有只含 k 种类型字符的子串中,找出最长的那一子串,返回它的长度。

【Excepted】:

  • Time Complexity: O(|S|).
  • Auxiliary Space: O(|S|).

这道题目的重点在于,当左侧的指针需要移动时,它应该移动到哪一个字符上面?

错误的思路1:直接让 left 从左侧开始移动,当遇到一个新类型字符时停止。

错误的思路2:从当前位置往左计算,当计算的字符类型数量达到 k 时就停止。虽然可以改正该思路,但复杂度提高了。

AC 思路:

  • 子串用两个指针 left, right 来表示,同时用一个 set 保存子串中的字符类型
  • 当 set 的大小等于 k 时,更新最大长度。
  • 当 set 的大小大于 k 时,就需要移动(最短距离) left 来保证 set 大小等于 k。这里采用的方法如下:
    • 利用一个 map 存储当前子串中各类字符的数量
    • 让 left 移动,每次移动都从 map 中减去对应字符的数量,当该字符数量等于 0 时,说明当前 set 大小等于 k。

Python3

【评论区】

py
from collections import defaultdict
class Solution:

    def longestKSubstr(self, s, k):
        if k < 1 or len(s) < 1:
            return -1

        ans = -1
        left, right, n = 0, -1, len(s)
        map_char_idx = defaultdict(lambda: 0)

        while right < n-1:
            right += 1
            map_char_idx[s[right]] += 1

            if len(map_char_idx) < k:
                continue

            while len(map_char_idx) > k:
                map_char_idx[s[left]] -= 1
                if map_char_idx[s[left]] == 0:
                    del map_char_idx[s[left]]
                left += 1

            ans = max(ans, right - left + 1)

        return ans

【Hint 思路】

py
from collections import defaultdict
class Solution:

    def longestKSubstr(self, s, k):
        if k < 1 or len(s) < 1:
            return -1

        max_len = -1
        left, right = 0, -1
        unique_char = set()
        char_num = defaultdict(lambda: 0)

        for char in s:
            right += 1
            unique_char.add(char)
            char_num[char] += 1

            if len(unique_char) == k:
                max_len = max(max_len, right - left + 1)
            elif len(unique_char) > k:
                while True:
                    if char_num[s[left]] > 1:
                        char_num[s[left]] -= 1
                        left += 1
                    else:
                        char_num[s[left]] -= 1
                        unique_char.remove(s[left])
                        left += 1
                        break

        return max_len

【866 /1120】超时代码,对我最开始的思路进行修正而实现的代码。说明思路大题每次,但是效率不行!

py
class Solution:

    def longestKSubstr(self, s, k):
        if k < 1 or len(s) < 1:
            return -1

        max_len = -1
        left, right = 0, -1
        unique_set = set()

        def update_unique_set(right):
            new_set = set()
            while len(new_set) < k:
                new_set.add(s[right])
                right -= 1
            while s[right] in new_set:
                right -= 1
            return new_set, right + 1

        right = 0
        n = len(s)
        for right in range(n):
            char = s[right]
            unique_set.add(char)
            if len(unique_set) < k:
                continue
            if len(unique_set) > k:
                unique_set, left = update_unique_set(right)
            max_len = max(max_len, right - left + 1)

        return max_len