力扣459. 重复的子字符串

重复的子字符串:Java解法详解

来源:459. 重复的子字符串 - 力扣(LeetCode)

题目

 

给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。

示例 1:

输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。

示例 2:

输入: s = "aba"
输出: false

示例 3:

输入: s = "abcabcabcabc"
输出: true
解释: 可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)

提示:

  • 1 <= s.length <= 104
  • s 由小写英文字母组成

 详解

方法一:枚举法(滑动窗口思想)

思路

题目意思是判断一个字符串能否由其子串多次重复构成,可以提取三个重要点:

  • 主串 一定是 子串长度 的倍数;

  • 子串 长度一定小于或等于 主串 长度的一半;

  • 子串 一定是 主串 的前缀;

 代码

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;
    }
}

详细执行过程

  1. 获取字符串长度:首先,代码获取输入字符串 s 的长度 n

  2. 遍历可能的子串长度:使用一个循环从 1 到 n/2 遍历可能的子串长度 i。这里只需要遍历到 n/2,因为如果一个子串的长度超过 n/2,它不可能重复多次来构成 s

  3. 检查是否为子串的倍数:在每次循环中,首先检查 n 是否能被 i 整除。如果 n 能被 i 整除,说明 s 可以被分成若干个长度为 i 的子串。

  4. 匹配子串:如果 n 能被 i 整除,进入内层循环,从位置 i 开始遍历字符串 s,检查每个字符是否与其对应的前一个子串中的字符相同。具体来说,检查 s.charAt(j) 是否等于 s.charAt(j - i)

  5. 判断匹配结果

    • 如果在内层循环中发现任何不匹配的字符,将 match 标志设为 false 并跳出循环。
    • 如果所有字符都匹配,说明整个字符串可以由长度为 i 的子串重复构成,返回 true
  6. 返回结果:如果遍历完所有可能的子串长度后仍未找到匹配的子串,则返回 false,表示字符串 s 不能由某个子串重复多次构成。

方法关键(滑动窗口)

s.charAt(j) != s.charAt(j - i)

 比较字符串 s 中两个位置的字符是否相等。具体来说,它是在检查字符串 s 中索引为 j 的字符和索引为 j - i 的字符是否相同。

举例

对于输入字符串 asdasdasd,我们来逐步分析该算法的执行过程:

  1. 字符串长度:首先计算字符串 asdasdasd 的长度,得到 n = 9

  2. 遍历可能的子串长度:根据算法,我们从 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 类的一个方法,用于从字符串中提取子串。它有两个重载版本:

  1. public String substring(int beginIndex)

    • 该方法返回从指定索引 beginIndex 开始到字符串末尾的子串。
    • 例如,"hello".substring(2) 将返回 "llo"
  2. public String substring(int beginIndex, int endIndex)

    • 该方法返回从指定索引 beginIndex 开始,到 endIndex 结束(不包括 endIndex)的子串。
    • 例如,"hello".substring(1, 4) 将返回 "ell"

参数说明

  • beginIndex:子串的起始索引(包含)。
  • endIndex:子串的结束索引(不包含)。

注意事项

  • 索引从 0 开始。
  • 如果 beginIndex 和 endIndex 相同,返回的子串为空字符串。
  • 如果 beginIndex 大于 endIndex 或任一索引超出字符串长度,会抛出 StringIndexOutOfBoundsException 异常。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值