给定一个非空的字符串 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