重复的子字符串:Java解法详解
来源:459. 重复的子字符串 - 力扣(LeetCode)
题目
给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。
示例 1:
输入: s = "abab" 输出: true 解释: 可由子串 "ab" 重复两次构成。
示例 2:
输入: s = "aba" 输出: false
示例 3:
输入: s = "abcabcabcabc" 输出: true 解释: 可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)
提示:
1 <= s.length <= 104s由小写英文字母组成
详解
方法一:枚举法(滑动窗口思想)
思路
题目意思是判断一个字符串能否由其子串多次重复构成,可以提取三个重要点:
-
主串 一定是 子串长度 的倍数;
-
子串 长度一定小于或等于 主串 长度的一半;
-
子串 一定是 主串 的前缀;
代码
class Solution {
public boolean repeatedSubstringPattern(String s) {
int n = s.length();
for (int i = 1; i * 2 <= n; ++i) {
if (n % i == 0) {
boolean match = true;
for (int j = i; j < n; ++j) {
if (s.charAt(j) != s.charAt(j - i)) {
match = false;
break;
}
}
if (match) {
return true;
}
}
}
return false;
}
}
详细执行过程
-
获取字符串长度:首先,代码获取输入字符串
s的长度n。 -
遍历可能的子串长度:使用一个循环从
1到n/2遍历可能的子串长度i。这里只需要遍历到n/2,因为如果一个子串的长度超过n/2,它不可能重复多次来构成s。 -
检查是否为子串的倍数:在每次循环中,首先检查
n是否能被i整除。如果n能被i整除,说明s可以被分成若干个长度为i的子串。 -
匹配子串:如果
n能被i整除,进入内层循环,从位置i开始遍历字符串s,检查每个字符是否与其对应的前一个子串中的字符相同。具体来说,检查s.charAt(j)是否等于s.charAt(j - i)。 -
判断匹配结果:
- 如果在内层循环中发现任何不匹配的字符,将
match标志设为false并跳出循环。 - 如果所有字符都匹配,说明整个字符串可以由长度为
i的子串重复构成,返回true。
- 如果在内层循环中发现任何不匹配的字符,将
-
返回结果:如果遍历完所有可能的子串长度后仍未找到匹配的子串,则返回
false,表示字符串s不能由某个子串重复多次构成。
方法关键(滑动窗口)
s.charAt(j) != s.charAt(j - i)
比较字符串 s 中两个位置的字符是否相等。具体来说,它是在检查字符串 s 中索引为 j 的字符和索引为 j - i 的字符是否相同。
举例
对于输入字符串 asdasdasd,我们来逐步分析该算法的执行过程:
-
字符串长度:首先计算字符串
asdasdasd的长度,得到n = 9。 -
遍历可能的子串长度:根据算法,我们从
1到n/2(即4)遍历可能的子串长度i。-
i = 1:
- 检查
n是否能被1整除,显然可以。 - 进行匹配检查:逐个比较每个字符与其前一个位置的字符。
s.charAt(1) != s.charAt(0),即's'和'a'不相等。
- 匹配失败,
match为false,跳出内层循环。
- 检查
-
i = 2:
- 检查
n是否能被2整除,显然不能(9 不能被 2 整除),因此跳过这个长度。
- 检查
-
i = 3:
- 检查
n是否能被3整除,可以(9 能被 3 整除)。 - 进行匹配检查:
s.charAt(3) == s.charAt(0),即'a'和'a'相等。s.charAt(4) == s.charAt(1),即's'和's'相等。s.charAt(5) == s.charAt(2),即'd'和'd'相等。s.charAt(6) == s.charAt(3),即'a'和'a'相等。s.charAt(7) == s.charAt(4),即's'和's'相等。s.charAt(8) == s.charAt(5),即'd'和'd'相等。
- 所有字符都匹配,说明整个字符串可以由长度为
3的子串'asd'重复构成,返回true。
- 检查
-
若仍有疑问,可直接运行下方完整代码进行调试。建议设置断点逐步跟踪执行流程,这样能更直观地理解程序的运行过程。
class Solution {
public boolean repeatedSubstringPattern(String s) {
int n = s.length();
for (int i = 1; i * 2 <= n; ++i) {
if (n % i == 0) {
boolean match = true;
for (int j = i; j < n; ++j) {
if (s.charAt(j) != s.charAt(j - i)) {
match = false;
break;
}
}
if (match) {
return true;
}
}
}
return false;
}
}
public class Main {
public static void main(String[] args){
Solution solution = new Solution();
String test1 = "aba";
// 调用方法并输出结果
System.out.println("Test 1: " +
solution.repeatedSubstringPattern(test1)); // 应输出 true
}
}
方法二(拼接检测方法)
要判断主串是否由子串重复构成,可以采用拼接检测方法:取出潜在子串并添加到主串末尾,同时移除主串前端等长子串。若处理后字符串与原主串相同,则证明主串确实由该子串重复构成。
class Solution {
public boolean repeatedSubstringPattern(String s) {
for (int i = 1;i*2 <= s.length(); i++) {
//将s.chatAt(i)的元素拼接到s后面
String str = s.substring(0, i);
//将s.chatAt(i)的元素拼接到s后面
String str2 = s + str;
//拿到str2里面从i之后的元素
String str3 = str2.substring(i);
if (str3.equals(s)){
return true;
}
}
return false;
}
}
知识点
s.substring()
substring 方法是 Java 中 String 类的一个方法,用于从字符串中提取子串。它有两个重载版本:
-
public String substring(int beginIndex):- 该方法返回从指定索引
beginIndex开始到字符串末尾的子串。 - 例如,
"hello".substring(2)将返回"llo"。
- 该方法返回从指定索引
-
public String substring(int beginIndex, int endIndex):- 该方法返回从指定索引
beginIndex开始,到endIndex结束(不包括endIndex)的子串。 - 例如,
"hello".substring(1, 4)将返回"ell"。
- 该方法返回从指定索引
参数说明
beginIndex:子串的起始索引(包含)。endIndex:子串的结束索引(不包含)。
注意事项
- 索引从 0 开始。
- 如果
beginIndex和endIndex相同,返回的子串为空字符串。 - 如果
beginIndex大于endIndex或任一索引超出字符串长度,会抛出StringIndexOutOfBoundsException异常。

526

被折叠的 条评论
为什么被折叠?



