📌  相关文章
📜  国际空间研究组织 | ISRO CS 2016 |问题 13(1)

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

国际空间研究组织 | ISRO CS 2016 |问题 13

这是 ISRO CS 2016考试中的第13个问题。下面将介绍该问题以及其解决方法。

问题描述

给定一个字符串S和一个整数K,找到字符串中长度为K的所有不同子串的个数。

例如,如果S="abcabc",K=3,则有4个不同的子串:“abc”,“bca”,“cab”和“abc”。

解决方法
方法一:暴力枚举

我们可以使用两个嵌套的循环来枚举字符串S中所有长度为K的子串,并将它们存储在一个集合中,以便去除重复的子串。最后,我们只需要返回集合的大小即可。

def count_substrings(S, K):
    unique_substrings = set()
    for i in range(len(S) - K + 1):
        substring = S[i:i+K]
        unique_substrings.add(substring)
    return len(unique_substrings)

时间复杂度:$O(n^2)$,其中n是字符串S的长度。由于嵌套的循环,暴力枚举方法的时间复杂度为二次方级别。

方法二:滑动窗口

在暴力枚举方法中,我们多次计算相同的子串,这是由于我们是从左往右移动串,而子串则是从右往左移动的。我们可以通过滑动窗口方法来优化这个过程。

我们先计算字符串S的前K个字符的哈希值,并将其存储在一个集合中。然后,我们向右滑动该窗口直到其位于第i个字符。在每次移动时,我们首先从窗口中移除前一个字符的哈希值,然后计算下一个字符的哈希值,并将其添加到集合中。我们只需要保留集合中的不同子串,然后返回其大小即可。

具体实现步骤如下:

  1. 计算字符串S中前K个字符的哈希值,存储在hash_set中。
  2. 遍历字符串S,从第K个字符开始。
  3. 计算当前窗口中子串的哈希值,如果不在hash_set中,将其添加到hash_set中。
  4. 移动窗口:删除前一个字符的哈希值,计算下一个字符的哈希值,并将其添加到hash_set中。
  5. 返回hash_set的大小。

代码实现如下:

def count_substrings(S, K):
    unique_substrings = set()
    hash_set = set()
    
    # 计算前K个字符的哈希值
    hash_val = 0
    for i in range(K):
        hash_val = hash_val * 101 + ord(S[i])
    hash_set.add(hash_val)
    unique_substrings.add(S[:K])

    # 滑动窗口
    for i in range(K, len(S)):
        # 计算当前窗口的哈希值
        hash_val = hash_val * 101 - ord(S[i - K]) * 101 ** K + ord(S[i])
        if hash_val not in hash_set:
            hash_set.add(hash_val)
            unique_substrings.add(S[i-K+1:i+1])
    
    return len(unique_substrings)

时间复杂度:$O(n)$,其中n是字符串S的长度。在每个窗口中,我们只需要一次哈希计算,而哈希计算的时间复杂度是常数级别的,因此滑动窗口方法的时间复杂度为线性级别。