这道题的暴力方法是枚举所有的substring,然后存储在集合里。虽然看上去时间复杂度是o(N^2),但是对于长字符串的集合存储和查询的开销非常大,事实上不可以用o(1)时间来忽略。
我们在考虑类似axxxxaxxxxx
的字符串时,需要解决的一个问题是,以第二个a开头的子串axxx
是否会和以第一个a开头的子串axxx
重复。为了避免用字符串集合来暴力查询,我们可以用字典树。我们在处理第一个a时,就把以其为开头的substring存入一个trie(此时这个trie没有任何分支,应该是一条长链)。这样当我们处理以第二个a为开头的substring时,就从trie里顺着a这条分支往下走,如果有任何重合的部分,都不算distinct substring。直至当前的substring延伸到一定程度之后不再与Trie中的已有路径重合,我们就在Trie里继续往下开辟新的路径和节点。同时每开辟新的一层,就意味着多了一个distinct substring。
这种做法的时间复杂度也是真o(N^2),每个基本操作就是遍历或创建Trie节点。但是当大量开辟动态空间时,也会造成TLE。
我们考虑固定长度len的滑窗,将滑窗范围内的字符串encode成一个数字放入集合里,就可以快速判断这个字符串是否之前出现过。编码的方法就是将这个字符串看成一个26进制的数,注意取模。窗口滑动的时候,针对老编码,用o(1)的时间加上新字符、减去老字符,就可以得到新的编码。
后缀树(数组)可以得到o(N)的优秀解法,但是我不会。