📌  相关文章
📜  大小为 k 的字典上最小和最大的子串(1)

📅  最后修改于: 2023-12-03 14:51:42.163000             🧑  作者: Mango

大小为 k 的字典上最小和最大的子串

给定一个字符串 S 和一个整数 k,找到 S 中长度为 k 的最小和最大子串。

算法思路
最小子串

最小子串可以通过滑动窗口算法实现,具体步骤如下:

  1. 初始化两个指针 left 和 right,分别指向字符串 S 的开头和 (k-1) 位置
  2. 初始化一个字典 cnt,用于记录当前滑动窗口中字符出现的次数
  3. 初始化一个变量 min_substring,表示当前找到的最小子串
  4. 遍历字符串 S,不断移动指针 right,更新 cnt 中对应字符出现的次数
  5. 如果当前滑动窗口中的子串长度等于 k,则检查 cnt 中是否包含了所有 k 个字符
  6. 如果 cnt 中包含了所有 k 个字符,则更新 min_substring
  7. 继续移动指针 left,同时更新 cnt 中对应字符出现的次数,直到 cnt 中不再包含所有 k 个字符
  8. 重复步骤 4 - 7,直到右指针越界停止
最大子串

最大子串可以通过构造字符串数组实现,具体步骤如下:

  1. 构造一个字符串数组 str,每个字符串包含 k 个字符,按字典序递增排序
  2. 遍历字符串 S,将长度为 k 的子串加入到一个新的数组 sub 中
  3. 对数组 sub 排序,然后依次在数组 str 中查找 sub 中是否存在某个字符串
  4. 如果存在,则更新结果字符串
代码实现
最小子串
def min_substring(S: str, k: int) -> str:
    left = 0
    right = k - 1
    cnt = {}
    min_substring = S + "1"  # 设置初始最小子串为 S 加上一个大于 S 的字符

    # 初始化 cnt
    for i in range(left, right + 1):
        c = S[i]
        cnt[c] = cnt.get(c, 0) + 1

    while right < len(S):
        # 检查当前滑动窗口中是否包含所有 k 个字符
        if len(cnt) == k:
            # 更新最小子串
            if S[left : right + 1] < min_substring:
                min_substring = S[left : right + 1]

            # 移动左指针,并更新 cnt
            c = S[left]
            cnt[c] -= 1
            if cnt[c] == 0:
                del cnt[c]
            left += 1

        else:
            # 移动右指针,并更新 cnt
            right += 1
            if right < len(S):
                c = S[right]
                cnt[c] = cnt.get(c, 0) + 1

    return min_substring if min_substring != S + "1" else ""
最大子串
def max_substring(S: str, k: int) -> str:
    # 构造字符串数组 str
    str = []
    for i in range(0, 26 ** k):
        s = ""
        n = i
        for j in range(k):
            c = chr(ord('a') + n % 26)
            s += c
            n //= 26
        str.append(s)

    sub = []
    for i in range(len(S) - k + 1):
        sub.append(S[i:i+k])

    # 对 sub 和 str 排序
    sub.sort()
    str.sort()

    for s in sub:
        if s in str:
            return s

    return ""
总结

最小子串使用滑动窗口算法,时间复杂度为 O(n);最大子串使用字符串数组构造,时间复杂度为 O(26^k)(即最大字符串数组长度)。