22、★★KMP算法进一步学习-459.重复的子字符串

题目描述:

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

子串不包括本身

思路:

1)主串和子串的问题,首先想到 KMP算法;可能讲不太清楚,但是掌握的内容足够说的尽量清楚;但是这道题后续的思维,不容易捋顺:

可用子串重复,子串最大长度为 n/2;一定是小于等于 n/2的;等于时很容易理解!

小于 n / 2时,其最后位置上的 next数值一定大于 n / 2;有一部分前后缀是重叠的;减去前缀剩下的一部分一定是 可重复的子串!

2)KMP算法中next数组的构建:while和for两种循环有所不同

for:

        int size = s.length();
        int[] next = new int[size];
        int now = 0;//此时代表的也是 next[0]的值,此时为0
        //注意 now的值和 数组下标的对应关系;now刚好是最大公共前后缀后一位的位置!
        for(int i = 1;i < size;i++){//从一开始构造
            if(s.charAt(i) == s.charAt(now)){
                now++;//now后移
                next[i] = now;
            }
            //此时不相同了,就是后缀长度不能加1;甚至一个都没有;要循环回去
            else if(now != 0){
                //直接在上一个位置的 最大前后缀的字符串里 往前找
                now = next[now - 1];
                //此时后面 i 不能加1
                //使用 while和此不一样
                i--;
            }
            else{
                //此时往前找到了头now = 0;并且还不相等,就是首位都不相等
                next[i] = now;
            }
        }

while:

        int[] next = new int[p.length];
        int now = 0;//其实就是第一个位置 index为0时,next数组的元素
        int i = 1;
        while(i < p.length){
            //如果后缀加一,与前缀加一的位置相同,就在该位置的next 加以
            if(p[i] == p[now]){
                now++;
                next[i] = now;
                i++;
            }
            //如果加一不相等,且此时还没到最初的位置,则
            else if(now != 0){
                now = next[now - 1];
            }
            //如果已经到了头 就是p[i] != p[now] && now == 0
            else{
                next[i] = now;
                i++;
            }
        }

代码:

1)KMP算法 + 思维的构建

class Solution {
   public boolean repeatedSubstringPattern(String s) {
        //next数组
        int size = s.length();
        int[] next = new int[size];
        int now = 0;//此时代表的也是 next[0]的值,此时为0
        //注意 now的值和 数组下标的对应关系;now刚好是最大公共前后缀后一位的位置!
        for(int i = 1;i < size;i++){//从一开始构造
            if(s.charAt(i) == s.charAt(now)){
                now++;//now后移
                next[i] = now;
            }
            //此时不相同了,就是后缀长度不能加1;甚至一个都没有;要循环回去
            else if(now != 0){
                //直接在上一个位置的 最大前后缀的字符串里 往前找
                now = next[now - 1];
                //此时后面 i 不能加1
                //使用 while和此不一样
                i--;
            }
            else{
                //此时往前找到了头now = 0;并且还不相等,就是首位都不相等
                next[i] = now;
            }
        }
        //创建好了next数组

        //本题的判断;如果存在重复字符串,前后缀表一定大于一半;且剩下的还能组成完整的字符串
        if(next[size - 1] != 0 && size % (size - next[size - 1]) == 0) return true;
        return false;
    }
}

2)使用API;结合移动的思想;但是时间复杂度很高!

class Solution {
   public boolean repeatedSubstringPattern(String s) {
        String str = s + s;
        return str.substring(1, str.length() - 1).contains(s);
   }
}

作者:13217319563
链接:https://leetcode-cn.com/problems/repeated-substring-pattern/solution/jian-dan-ming-liao-guan-yu-javaliang-xing-dai-ma-s/
来源:力扣(LeetCode)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值