【力扣 459】重复的子字符串 C++题解(子字符串+字符串匹配)

52 阅读2分钟

给定一个非空的字符串 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的返回值进行了处理。这样,如果找到sfind返回非负数,~find返回负数,转换为布尔值为true;如果找不到sfind返回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