28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)
1. 文章链接
2. 看到题目的第一想法
想都不要想,想不出来的。
3. 看完代码随想录之后的想法
关键在于构建前缀表。
- 初始化一个前缀
head_str末尾指针j, for循环一个模式串字串末尾位置遍历,其中i表示字串末尾,也即尾缀tail_str末尾:- 如果
head_str[j]!=tail_str[i],就要一直往前退。例如"aabaaf"中,如果i=4指向的倒数第一个'a',则j=1,现在i要指向'f'时,则j=j+1后指向'b'。两者不相等,j就要一直向后退,退到template[:j+1]能够出现在template[?~i+1]中。 实际上就是前缀表table[:j+1]现在充当了用template[:j+1]去匹配template[?~i+1]字串的前缀表,且必须从匹配上后面的连续字符,而非这个字串的任意位置。 - 如果
head_str[j]==tail_str[i],就要推进j。 - 然后将
j记录到当前的前缀表table[i]。这里要注意前缀表i号单元存的就是template[:i+1]的最长相等前后缀长度。
- 如果
4. 实现过程中遇到的困难
class Solution:
def build_table(self, template: str) -> list:
j = 0 t_list = list(template)
table = [j] * len(t_list)
for i in range(1, len(t_list)):
while (j > 0) and (t_list[j] != t_list[i]): # 一定要大于0,不然table[j-1]没办法取。
j = table[j - 1]
if t_list[j] == t_list[i]:
j += 1
table[i] = j
return table
def strStr(self, haystack: str, needle: str) -> int:
table = self.build_table(needle)
haystack_list = list(haystack)
needle_list = list(needle)
j = 0
for i in range(0, len(haystack_list)):
while (j > 0) and (haystack_list[i] != needle_list[j]):
j = table[j - 1]
if needle_list[j] == haystack_list[i]:
j += 1
if j == len(needle_list):
return i + 1 - len(needle_list)
return -1
- 我喜欢前缀表不统一减一的构建方法,这样直观,
table[i]一定表示了包括i号位在内的整个模板串的子串的最长相等前后缀的长度。 - 如果
j=0而非统一减一的j=-1,那么判断不相等后不断往回退的while必须加上j>0的条件,这样才能用j = table[j - 1]向前退。 - 构建前缀表时
i应该从1开始,不然template[j]==template[i]就一直成立了。注意后缀的定义是不能包括第一个元素的。 - 在真正对文本串用模板串匹配时,
for循环的i却要从0开始,因为这不是前缀去匹配后缀的构建前缀表过程,而是两个互不相交的串匹配了,得从0开始。
5.学习时长
2小时。
459. 重复的子字符串 - 力扣(LeetCode)
1. 文章链接
2. 看到题目的第一想法
还是没有想法,除非一个一个试,试每一个字串能不能把整个文本串都匹配一遍。
3. 看完代码随想录之后的想法
在由重复子串组成的字符串中,最长相等前后缀不包含的子串就是最小重复子串。 这个结论我看不到显式的证明方法,但是也举不出反例。
class Solution:
def build_table(self, template: str) -> list:
j = 0
t_list = list(template)
table = [0] * len(t_list)
for i in range(1, len(t_list)):
while (j > 0) and (template[j] != template[i]):
j = table[j - 1]
if template[j] == template[i]:
j += 1
table[i] = j
return table
def repeatedSubstringPattern(self, s: str) -> bool:
table = self.build_table(template=s)
repeat_len = len(list(s)) - table[-1]
if repeat_len != len(list(s)) and len(list(s)) % repeat_len == 0:
return True
else:
return False
4. 实现遇到的困难
注意一定要是前缀表的最后一个元素记录的长度,而非最大长度。
5. 学习时长
30分钟。