LeetCode
- 题目地址:https://leetcode.com/problems/repeated-substring-pattern/?tab=Description
解题思路:简单描述一下题目,就是输入是一个字符串,问该字符串能否由它的子串多次复制而得。注释中包含了思路,主要参考https://discuss.leetcode.com/topic/67652/c-o-n-using-kmp-32ms-8-lines-of-code-with-brief-explanation/2
考虑到在注释中显示效果不好,所以把也用文字描述一遍:
首先i,j表示两个下标,i表示当前下标,j表示与i差一个循环子串的坐标。比如str=”abab”,i=2(a)的时候,j=0(a),并用dup的数组记录下来,要注意的是这里dup[3]=1,因为若是dup[i=2]=j=0的话,j走到2的时候发现循环不匹配的返回j=0,而s[j=0]和s[j=2]对应的字符相同,比较没意义,所以是i++和j++过后,再给dup赋值。判断s[i]与s[j]是否相等,有以下三种情况:- 相等:如果相同,说明是重复的,那么i和j都往下走一步,同时给dup数组赋值
- 不相等且j=0:这时候str[i] != str[j],如果j=0即指向头,说明没找到重复的子串,这时候j不变,i继续往下走,如果到了重复的子串的开头,那么就会到情况1
- 不相等且j不为0:即原本已经找到重复的子串,但是再往下走没有满足重复子串的复制条件,比如”ababacababac”,一开始找到”ab”作为复制子串,后来是”ababac”,说明可能是有字符长度更大的子串作为重复子串,那么返回上一个循环中的位置
最后考虑两种情况:一是整个字符串没有重复的子串,一直处于情况2所以dup[n]在结束的时候仍然等于0;还有一种情况或者说要求,最后一个子串的长度要被总长度整除,最后一个子串代表整个字符串遍历一遍后,最终确定的长度最大的重复子串(如果存在重复子串的话),n-dup[n]表示最后一个子串的长度
代码如下:
class Solution { public: bool repeatedSubstringPattern(string s) { int i = 1, j = 0, n = s.size(); vector<int> dup(n+1,0); //i,j表示两个下标,i表示当前下标,j表示与i差一个循环子串的坐标 //比如str="abab",i=2(a)的时候,j=0(a),并用dup的数组记录下来 //要注意的是这里dup[3]=1,因为若是dup[i=2]=j=0的话,j走到2的时候发现循环不匹配的返回j=0,而s[j=0]和s[j=2]对应的字符相同,比较没意义,所以是i++和j++过后,再给dup赋值 while (i < s.size()) { //情况1:如果相同,说明是重复的,那么i和j都往下走一步,同时给dup数组赋值 if (s[i] == s[j]) { i++; j++; dup[i]=j; } //情况2:这时候str[i] != str[j],如果j=0即指向头, //说明没找到重复的子串,这时候j不变,i继续往下走, //如果到了重复的子串的开头,那么就会到情况1 else if (j == 0) { i++; } //情况3:循环不匹配,且j不为0,即已经找到重复的子串,但是没有满足重复子串的复制条件,比如"ababacababac",说明可能是有字符长度更大的子串作为重复子串,那么返回上一个循环中的位置 else { j = dup[j]; } } //考虑两种情况:一是整个字符串没有重复的子串,一直处于情况2所以dup[n]在结束的时候仍然等于0;还有一种情况,最后一个子串的长度要被总长度整除,最后一个子串代表整个字符串遍历一遍后,最终确定的长度最大的重复子串(如果存在重复子串的话),n-dup[n]表示最后一个子串的长度 return dup[n] && n % (n-dup[n]) == 0; } };