Unique Substrings in Wraparound String
Consider the string s to be the infinite wraparound string of
"abcdefghijklmnopqrstuvwxyz"
, so s will look like this:
"...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd...."
.Now we have another string p. Your job is to find out how many unique
non-empty substrings of p are present in s. In particular, your input
is the string p and you need to output the number of different
non-empty substrings of p in the string s.Note: p consists of only lowercase English letters and the size of p
might be over 10000.Example 1: Input: “a” Output: 1
Explanation: Only the substring “a” of string “a” is in the string s.Example 2: Input: “cac” Output: 2
Explanation: There are two
substrings “a”, “c” of string “cac” in the string s.Example 3: Input:
“zab” Output: 6 Explanation: There are six substrings “z”, “a”, “b”,
“za”, “ab”, “zab” of string “zab” in the string s.
定义"...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd...."
为循环字符串,并给定字符串p,要求在p的所有非空子串中,找出出现在循环字符串中那些子串。
题目分析
这题有一个隐藏的重要条件,就是这个循环字符串。该循环字符串并不是任意字符串的循环体,而是规定了是"abcdefghijklmnopqrstuvwxyz"
的循环体,里面所有字母都是由abcd的顺序前后相连的。所以其实题目的意思是,找出字符串p所有子串中,每个字母按照字母表顺序相连的子串。比如,如果p是xyzabcd
,那像xyz
或者xyzabcd
或者bcd
这些子串,它们的字母都是按照字母表顺序相连的(为了省略篇幅,未穷举完所有可能)。按照字母表顺序相连,即意味着前字符的ascii码比后字符小1,或者后字符比前字符小25(za
的情况)。
动态规划
复杂度
时间 O(N) 空间 O(1)
思路分析
- 由于符合条件的子串中字符是顺序相连的,所以如果前两个字符组成的子串是符合条件的话,如果第三个字符和第二个字符也是相连的,那这三个字符组成的子串肯定也是符合条件的
- 也是由于符合条件的子串中字符是顺序相连的,那么这个子串的长度有多长,就有多少种以该子串最后一个字符为结尾的小子串。比如
abcd
这个长度为4的子串,以d结尾有4中可能:d, cd, bcd, abcd
- 由于题目只要求找出唯一的子串数量,那么以某一个字符为结尾的子串,无论改字符出现在哪,它所可能组成的子串都是一样的,所以我们只需要找到能组成最长子串的那个位置就行了。比
abcdxybcd
中,以d结尾的子串必定是abcd, bcd, cd, d
,所以第二次遇到b,c,d
时,由于所组成子串长度不及第一次出现时子串的最大长度,所以就不用考虑了 - 那么根据前三点,我们只要找出p中每个字符所能组成的唯一子串数量,再把它们相加,就是p中所有符合条件的子串数量了
class Solution:
def findSubstringInWraproundString(self, p):
"""
:type p: str
:rtype: int
"""
count = [0 for i in range(0, 26)]
length = 1
if len(p) > 0:
count[ord(p[0]) - ord('a')] = 1 # 以第一个字符结尾的子串长度为1
for index in range(1, len(p)): # 从第二个字符开始,看时候能和前一个字符相连
isConsecutive = ord(p[index]) - ord(p[index - 1]) == 1 or ord(p[index - 1]) - ord(p[index]) == 25
if isConsecutive: # 如果是顺序相连的,那么当前能组成的子串最大长度加1
length += 1
else:
length = 1 # 如果这个顺序被断开了,那么当前能组成的子串最大长度重置为1
ascii = ord(p[index]) - ord('a')
count[ascii] = max(count[ascii], length) # 记录以当前字符结尾的子串能达到的最大长度
return sum(count) # 每个字符的最大长度,都代表这个字符结尾的唯一子串的数量,相加既是所有唯一子串数量