长度为K的不同子字符串的数量——问题与方法

389 阅读3分钟

在这篇文章中,我们解释了使用滚动哈希技术、哈希表和暴力方法来寻找长度为K的不同子字符串的方法。

内容表

  1. 问题陈述
  2. 方法1 - 蛮力
  3. 方法2 - 使用哈希表
  4. 方法3 - 滚动哈希算法

我们现在将深入研究 "长度为K的不同子串的数量 "这一问题。

问题说明

给出一串小写字母和一个整数k作为输入,打印所有可能的子串的数量,其中正好有k个不同的字符。

Enter the string: abcd
Enter k value: 1
Total substrings with exactly 1 distinct characters : 4

Enter the string: mqtt
Enter k value: 2
Total substrings with exactly 2 distinct characters : 3

Enter the string: aaaa
Enter k value: 2
Total substrings with exactly 2 distinct characters : 0

方法1 - 蛮力

假设字符串的长度为n,那么可能有__n__(n+1)/2个子串*。一个简单而直接的方法是生成所有子串,并检查它是否正好有k个独特的字符。

循环生成所有的组合,然后检查是否有独特的字符,这样做成本很高,复杂度也高。

n(n+1)/2 = (n^2+1)/2 = O(n^2)

所以,生成字符串的复杂度顺序是O(n^2)。
下一步是检查每一个组合,这将需要O(n),使得整体复杂度为O(n^3)。
空间复杂度 - O(n)

方法2 - 使用哈希表

考虑到字符串只包含小写字母。主要概念是维护子串的哈希表并检查唯一字符的数量。

什么是哈希表?它是一种实现数组数据类型的数据结构,其中每个数组都与值相关,即它有键和值。它也被称为哈希表。

  • 首先,在程序中初始化计算所需的变量,如计数和存储字符的数组。
  • 循环查找子串,并进一步查找其中的不同字符数。
  • 最后,返回结果。
def count_k_dist(input_str, k):
    n = len(input_str)

    # Initializing res to 0,return after res after counting
    res = 0

    # To store count of characters from
    # 'a' to 'z'
    cnt = [0] * 27

    # For considering all substring beginning with input_str[i]
    for i in range(0, n):
        dist_count = 0

        # Initializing array with 0
        cnt = [0] * 27

        # Considering all substrings between str[i..j]
        for j in range(i, n):

            # If this is a new character for this
            # substring, increment dist_count.
            # ord(char) gives the ASCII value

            if cnt[ord(input_str[j]) - 97] == 0:
                dist_count += 1

            # Increment count of current character
            cnt[ord(input_str[j]) - 97] += 1

            # If distinct character count becomes k,
            # then increment result.
            if dist_count == k:
                res += 1
            if dist_count > k:
                break

    return res


if __name__ == "__main__":
    str1 = input("Enter the string: ")
    k = int(input("Enter k value: "))
    print("Total substrings with exactly", k,
          "distinct characters : ", end="")
    print(count_k_dist(str1, k))

时间复杂度:我们使用了两个嵌套的for循环,这使得时间复杂度为O(n*n)
空间复杂度:O(n)

方法3 - 滚动哈希算法

滚动散列(也被称为递归散列或滚动校验)是一个散列函数,输入在一个窗口中移动散列。

  • 首先,找到长度为'l'的第一个子字符串的哈希值。
  • 在它的帮助下,生成所有子串的哈希值,并将它们推入一个无序的集合。
  • 计算该集合中不同值的数量。
  • 因为有26个字符,所以用26来初始化x。
  • 找到哈希值并将其添加到无序集合中(元素是唯一的,没有顺序)。
  • 使用哈希值找出不同子字符串的数量。
# Python3 implementation of
x = 26
mod = 3001


# Function to find the required count
def count_substring(s, l):
    # Variable to the hash_val
    hash_val = 0

    # Finding hash_val of substring
    # (0, l-1) using random number x
    
    for i in range(l):
        hash_val = (hash_val * x + (ord(s[i]) - 97)) % mod

    # Computing x^(l-1)
    pow_l = 1
    for i in range(l - 1):
        pow_l = (pow_l * x) % mod

    # Unordered set to add hash_val values
    result = set()
    result.add(hash_val)

    # Generating all possible hash_val 
    for i in range(l, len(s)):
        hash_val = ((hash_val - pow_l * (ord(s[i - l]) - 97) + 2 * mod) * x + (ord(s[i]) - 97)) % mod

        result.add(hash_val)

    # Print the result
    print(len(result))


# Driver Code
if __name__ == "__main__":
    str1 = input("Enter the string:")
    k = int(input("Enter k value:"))

    count_substring(str1, k)

时间复杂度:O(n)
空间复杂度。O(n)

希望你喜欢解决这个问题,并学会如何使用OpenGenus的这篇文章来解决这个问题。 祝你
今天愉快,继续学习。