代码随想录字符串——重复的子字符串

题目

给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。

示例 1: 输入: “abab” 输出: True 解释: 可由子字符串 “ab” 重复两次构成。

示例 2: 输入: “aba” 输出: False

示例 3: 输入: “abcabcabcabc” 输出: True 解释: 可由子字符串 “abc” 重复四次构成。 (或者子字符串
“abcabc” 重复两次构成。)

思路

方法一
在一个串中查找是否出现过另一个串——>KMP算法

前缀表里统计了各个位置为终点字符串的最长相同前后缀的长度。(具体实现时:next数组=前缀表长度-1

若next[len - 1] != -1,则说明字符串有最长的相同的前后缀(就是字符串里的前缀子串和后缀子串相同的最长长度)。

最长相等前后缀的长度为:next[len - 1] + 1
因为这里next数组是以前缀表减一的方式计算

因为字符串s的最长相同前后缀的的长度一定是不包含s本身,所以 最长相同前后缀长度必然是(n-1) * x

在这里插入图片描述
即数组的长度减去最长相同前后缀的长度相当于是一个最小重复子串的长度(即一个周期的长度),如果这个周期可以被数组长度整除,说明整个数组就是这个周期的循环。

len % (len - (next[len - 1] + 1)) == 0

java代码如下:

class Solution {
	public boolean repeatedSubstringPattern(String s){
		if(s.equals("")) return false;
		int len = s.length();
		//原串加个空格(哨兵),让下标从1开始,这样j从0开始,也不用初始化了
		s = " " + s;
		char[] chars = s.toCharArray();//转化成字符数组
		int[] next = new int[len-1];//创建next数组
		//构造next数组,j从0开始,i从2开始
		for(int i =2,j = 0; i < len; i++){
			//匹配不成功,j回退到前一位置next数组所对应的值
			while(j > 0 && chars[i] != chars[j+1]) j = next[j];
			//匹配成功,i、j同时后移
			if(chars[i] == chars[j+1]) j++;
			//将最大相同前后缀长度j更新给next数组
			next[i] = j;
		}
		//最后判断是否是重复的子字符串,这里next[len]即代表数组末尾的值,因为加了一个空格
		if(next[len] > 0 && (len % next[len]) == 0){
		return true;
		}
		return false;
	}
}

方法二

如果字符串 S 包含一个重复的子字符串,那么这意味着可以多次 “移位”`字符串,并使其与原始字符串匹配。

其中避免一些无用的环绕,可以创建一个新的字符串 str,它等于原来的字符串 S 再加上 S 自身,这样其实就包含了所有移动的字符串

比如字符串:S = acd,那么 str = S + S = acdacd

acd 移动的可能:dac、cda。其实都包含在了 str 中了,就像一个滑动窗口

一开始 acd (acd) ,移动一次 ac(dac)d,移动两次 a(cda)cd。循环结束

所以可以直接判断 str去除首尾元素之后,是否包含自身元素。如果包含。则表明存在重复子串。

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HDU-五七小卡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值