给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。
示例 1:
输入: s = “abab”
输出: true
解释: 可由子串 “ab” 重复两次构成。
示例 2:
输入: s = “aba”
输出: false
示例 3:
输入: s = “abcabcabcabc”
输出: true
解释: 可由子串 “abc” 重复四次构成。 (或子串 “abcabc” 重复两次构成。)
提示:
1 <= s.length <= 104
s 由小写英文字母组成
思路
如果一个字符串是由其子串重复多次构成的,那么通过将两个这样的字符串连接起来,并移除第一个和最后一个字符,你仍然可以得到原始的字符串。
举个例子,假设我们有一个字符串 “abcabc”,它是由 “abc” 这个子串重复两次构成的。我们将两个 “abcabc” 连接起来得到 “abcabcabcabc”,然后移除第一个和最后一个字符得到 “bcabcabcab”。你会发现,原始的 “abcabc” 还在这个新的字符串中。
因此,我们可以通过创建字符串 s + s
,然后移除第一个和最后一个字符,看原始的字符串 s
是否还存在于新的字符串中。如果存在,那么 s
就是由其子串重复多次构成的。
首先,函数将s
与自身拼接,得到一个新的字符串s + s
。然后,函数从这个新字符串的第二个字符开始,取长度为s.length() * 2 - 2
的子串,即(s + s).substr(1, s.length() * 2 - 2)
。这个子串实际上就是去掉了第一个和最后一个字符的s + s
。
接着,函数在这个子串中查找s
,如果找到,就返回s
在子串中的位置,如果找不到,就返回string::npos
。在C++中,string::npos
的值等于-1,这是一个特殊的值,表示未找到。
然而,函数的返回值应该是一个布尔值,而不是一个整数。所以,函数使用了按位取反运算符~
对find
的返回值进行了处理。这样,如果找到s
,find
返回非负数,~find
返回负数,转换为布尔值为true
;如果找不到s
,find
返回string::npos
即-1,~find
返回0,转换为布尔值为false
。
AC代码
/** @lc app=leetcode.cn id=459 lang=cpp** [459] 重复的子字符串*/// @lc code=start
class Solution {
public:bool repeatedSubstringPattern(string s) {return ~(s + s).substr(1, s.length() * 2 - 2).find(s);}
};
// @lc code=end