📌  相关文章
📜  字典上最小的字符串,它不是给定字符串(1)

📅  最后修改于: 2023-12-03 15:25:02.481000             🧑  作者: Mango

寻找字典序最小的不在给定字符串中的字符串

这是一道经典的问题,要求从所有不在给定字符串中的字符串中找到字典序最小的一个。

解题思路

首先,我们需要明确一下,如何判断一个字符串 $s$ 是否在给定字符串集合 $S$ 中。最简单的方法是进行遍历比较,但时间复杂度为 $O(nm)$,其中 $n$ 表示 $S$ 中字符串的数量,$m$ 表示字符串的长度,显然这个方法不可取。

我们可以使用哈希表来判断一个字符串是否在集合中,这可以将时间复杂度降为 $O(m)$。具体实现中,我们将集合 $S$ 中的每个字符串的哈希值预处理出来。然后对于一个字符串 $s$,我们将其哈希值计算出来,再与集合 $S$ 中所有字符串的哈希值进行比较,如果存在相等的哈希值且字符串也相等,则 $s$ 在集合 $S$ 中,否则 $s$ 不在 $S$ 中。

接下来,我们需要构造一个字典序最小的不在 $S$ 中的字符串。显然,可以使用贪心的思想,尽量地让构造的字符串前缀与给定字符串相同,只需要在最后加上一个最小的不在 $S$ 中的字符即可。具体实现中,对于给定字符串的每个位置,我们将其尽可能地复制到答案字符串中,直到存在一种字符可以让答案字符串不在 $S$ 中为止。

代码实现
def find_dict_smallest_string(s: str, S: List[str]) -> str:
    S = set(S)
    seen = set()

    # 哈希函数
    def hash_fn(s: str) -> int:
        p, mod = 131, 10**9 + 7
        h = 0
        for c in s:
            h = (h * p + ord(c)) % mod
        return h

    # 构造字典序最小的字符串
    ans = []
    for i, c in enumerate(s):
        for nxt in range(ord('a'), ord(c)):
            new_s = ''.join(ans) + chr(nxt) + 'a' * (len(s) - i - 1)
            if hash_fn(new_s) not in seen and new_s not in S:
                ans.append(chr(nxt))
                seen.add(hash_fn(new_s))
                break
        else:
            ans.append(c)
    return ''.join(ans)
时间复杂度分析

哈希表判断集合成员的时间复杂度为 $O(m)$,考虑到本题所有字符串的总长度为 $O(mn)$,因此该步骤的时间复杂度为 $O(m^2n)$。构造字典序最小的字符串的过程中,每次需要遍历 $O(1)$ 个字符,因此时间复杂度也为 $O(m^2n)$。故总时间复杂度为 $O(m^2n)$。

空间复杂度分析

哈希表的空间复杂度为 $O(nm)$,见过程中并不需要使用额外的空间,因此总空间复杂度为 $O(nm)$。