📌  相关文章
📜  任意两次出现之间的最长子字符串-相似字符(1)

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

任意两次出现之间的最长子字符串-相似字符

题目描述:

给定一个字符串,请找出其任意两次出现之间的最长子字符串,满足该子字符串中相似字符的数量不少于k。其中,相似字符是指ASCII码值差值不超过1的字符。

算法思路:

  1. 遍历字符串,将相邻且ASCII码值差值不超过1的字符组成一个相似字符组。
  2. 使用哈希表记录每个相似字符组最后一次出现的位置。
  3. 对于每一个相似字符组,记录其在哈希表中的最后一次出现的位置。
  4. 如果当前字符是该相似字符组的结束字符,则更新该相似字符组在哈希表中的位置,否则添加该相似字符组到哈希表中。
  5. 如果相似字符组中的字符数不小于k,则更新最长子字符串长度。

时间复杂度:O(n)

空间复杂度:O(n)

代码实现:

def find_longest_substring(s: str, k: int) -> str:
    sim_chars = [] # 存储相似字符组的起始位置和相似字符数
    sim_char_index = {} # 存储相似字符组的最后一次出现位置

    i, length = 0, len(s)
    while i < length:
        # 相邻且ASCII码值差值不超过1的字符组成一个相似字符组
        j = i
        while j + 1 < length and abs(ord(s[j+1]) - ord(s[j])) <= 1:
            j += 1
        sim_chars.append((i, j - i + 1))
        i = j + 1

    longest_substring, current_substring = "", ""
    for i, (start, sim_char_cnt) in enumerate(sim_chars):
        # 如果相似字符组中的字符数不少于k
        if sim_char_cnt >= k:
            if current_substring:
                # 从当前位置开始,到相似字符组的结束位置为止,最大化字符串长度
                for j in range(start, sim_chars[i-1][0] + sim_chars[i-1][1]):
                    if j in sim_char_index and sim_char_index[j] >= sim_chars[i-1][0]:
                        sim_char_cnt += 1
                    # 更新相似字符组最后一次出现的位置
                    sim_char_index[j] = sim_chars[i-1][0] + sim_chars[i-1][1] - 1
                # 如果相似字符组中的字符数不小于k,则更新最长子字符串长度
                if sim_char_cnt >= k and len(current_substring) > len(longest_substring):
                    longest_substring = current_substring
            current_substring = s[start:start + sim_char_cnt]
        else:
            if current_substring:
                current_substring += s[start:start + sim_char_cnt]
    return longest_substring

注意事项:

  1. 本题中,相似字符指ASCII码值差值不超过1的字符。
  2. 须返回的是任意两次出现之间的最长子字符串,而不是最长相似字符组。
  3. 相似字符组的长度指的是相邻且ASCII码值差值不超过1的字符的总数,而不是相似字符的个数。
  4. 若题目中的k为0,则找出所有任意两次出现之间的最长子字符串。
  5. 本题还可以使用滑动窗口和二分法解答。