Leetcode459. 重复的子字符串【C++】

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

示例 1:

输入: "abab"

输出: True

解释: 可由子字符串 "ab" 重复两次构成。

示例 2:

输入: "aba"

输出: False

示例 3:

输入: "abcabcabcabc"

输出: True

解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。)

 

说是简单题目,但感觉应该接近中等题目的难度了。

说是一个字符串可由子字符串重复组成,那么字符串的长度必须是子串的整数倍,这样就可以少去很多的子串判断,并且字符串的每个子串部分的首字母head必然相同。

于是想到创建一个vector用来记录字符串每个首字母head的位置,而每个位置都可以确定一个子串,再由这些子串按滑动窗口的方式依次向后进行比对,程序中用times记录当前比较的次数以确定窗口的起始位置,窗口大小为子串长度,每次比对如果成功那么向后滑动一个当前子串的长度,如果失败则退出当前子串的比对,改为vector中下一个首字母head的位置重新创建一个子串,再重复上过程。如果最后比对到了字符串的尾部,则表示成功。注意字符串的长度必须子串的整数倍,否则就不用比对直接换到下一个子串。上代码:

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        int len = s.size();
        char head = s[0];
        vector<int> locs;
        for (int i = 1; i != len; ++i) {    //记录首字母在字符串中的位置
            if (s[0] == head)
                locs.push_back(i);
        }
        if (locs.empty())	return false;    //如果除了s[0]不存在其他的首字母,则必然为false
        int locsNum = 0;    //确定当前子串到哪一个首字母位置之前,以确定窗口大小
        string son = s.substr(0, locs[locsNum]);    //确定子串
        while (son.size() <= len / 2) {        //主循环,子串长度必须小于字符串的一半
            if (len % son.size() == 0) {    //判断字符串长度是否是子串的整数倍
                int times = 1;            //记录当前子串情况下已经进行比对的次数,初始为1表示自身与自身比对已经完成
                while (locs[locsNum] * times < len) {    //子串比较的循环,一直比较到字符串结尾
                    if (son != s.substr(locs[locsNum] * times, son.size()))//子串与滑动窗口在在字符串中的位置进行比对,如果不同则表示当前子串不符合要求,退出比较
                        break;
                    ++times;    //当前比较相同,更新times以将窗口向后滑动
                }
                if (locs[locsNum] * times == len)    //如果比对到了最后,表示符合要求,返回true
                    return true;
            }
            if ((++locsNum) == locs.size())    //表示所有首字母位置都已经用完也未找到适合的子串
                return false;
            son = s.substr(0, locs[locsNum]);    //重新选取子串
        }
        return false;    //子串长度已大于字符串的一半,未找到合适子串,返回false
    }
};

执行用时: 60 ms, 在Repeated Substring Pattern的C++提交中击败了25.42% 的用户。

用时有点多,感觉kmp算法也可以,但是理解的不深就不用了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值