686. 重复叠加字符串匹配
给定两个字符串 a 和 b,寻找重复叠加字符串 a 的最小次数,使得字符串 b 成为叠加后的字符串 a 的子串,如果不存在则返回 -1。
注意:字符串 "abc" 重复叠加 0 次是 "",重复叠加 1 次是 "abc",重复叠加 2 次是 "abcabc"。
示例 1:
输入:a = "abcd", b = "cdabcdab"
输出:3
解释:a 重复叠加三遍后为 "abcdabcdabcd", 此时 b 是其子串。
示例 2:
输入:a = "a", b = "aa"
输出:2
示例 3:
输入:a = "a", b = "a"
输出:1
自己的解题思路
首先,如果a中缺少b中的元素,那么无论a怎么重复b必定不能是a的子串。
那么如果a重复以后b是a的子串,那么第一个b的第一个元素就应该开始能够匹配的到
也就是 abcd中第一个b的元素c开始 cdabcdab刚好匹配到,从而计算出答案,代码如下
class Solution {
public:
int Isok(int index, string& a, string& b) { // 函数的作用是判断当前index是否满足条件
int ans = 1;
index--;
for(int i=0;i<b.size();i++) {
// int index_a = (index+1);
index++;
if(index>=a.size()) {
ans++;
index%=a.size();
}
if(a[index]!=b[i]) {
return -1;
}
}
return ans;
}
int repeatedStringMatch(string a, string b) {
/*
分析,也就是两个字符串 a b 寻找的是,b成为a重叠后的子串。
首次子串的概念就是,连续的,一致的,并不同于子序列
首先,重叠以后变成子串必须满足以下的条件
1. a中必须是b中开头的元素 abcd通过调整顺序就成了 cd开头的
*/
unordered_map<char,vector<int>> mp; // vector是为了防止有相同的字符。
for(int i=0;i<a.size();i++) {
mp[a[i]].push_back(i); // 记录的是字符出现的位置,
}
int ans= -1;
if(mp.find(b[0])==mp.end()) {
return ans;
}
for(auto index : mp[b[0]]) {
int tmp = Isok(index,a,b);
if(tmp>0) {
if(ans==-1) {
ans=tmp;
return ans;
} else {
ans=min(ans,tmp);
}
}
// cout<<ans<<endl;
}
return ans;
}
};
参考别人别人解题思路
首先,可以分析复制次数的「下界」和「上界」为何值:
对于「下界」的分析是容易的:至少将 a 复制长度大于等于 b 的长度,才有可能匹配。
在明确了「下界」后,再分析再经过多少次复制,能够明确得到答案,能够得到明确答案的最小复制次数即是上界。
由于主串是由 a 复制多次而来,并且是从主串中找到子串 b,因此可以明确子串的起始位置,不会超过 a 的长度。
由此,我们可知复制次数「上界」最多为「下界 + 11」。
令 a 的长度为 nn,b 的长度为 mm,下界次数为 c1,上界次数为 c2 = c1 + 1。
因此我们可以对 a 复制 c2 次,得到主串后匹配 b,如果匹配成功后的结束位置不超过了 n * c14,说明复制 c1 即可,返回 c1,超过则返回 c2;匹配不成功则返回 -1。
class Solution {
public:
int repeatedStringMatch(string a, string b) {
int m = a.size(), n = b.size();
//b如果有a没有的字符串,则返回-1
vector<int> alpha(26);
vector<int> start;//b[0]在a中的所有位置
for(int i = 0;i < m;i++)
{
alpha[a[i]-'a']++;
if(a[i] == b[0]){
start.push_back(i);
// printf("i:%d\n", i);
}
}
for(auto &c: b)
if(!alpha[c-'a']) return -1;
//a复制后长度必须不比b短才行
//思路:字符串哈希,记录a中b开头字母的位置
//a最大复制长度为b的两倍
//为了节省空间采用循环
int res = (n+m-1)/m;
int len_a = (n+m-1)/m * m;
bool flag = false;
int cnt = 2;
while(cnt--)
{
for(auto &pos: start)
{
for(int i = pos; i + n - 1 < len_a;i += m){
flag = true;
for(int j = i;j <= n+i-1;j++)
{
// printf("i:%d,j:%d,a:%c,b:%c\n",i,j,a[j%m],b[j-i]);
if(a[j%m] != b[j-i]) {
flag = false;
break;
}
}
if(flag) break;
}
if(flag) break;
}
if(flag) return res;
res += 1;
len_a += m;
}
return -1;
}
};
本文介绍了一种算法,用于解决字符串a重复叠加后使b成为其子串的问题。给出了两种解题思路,一种是通过判断a中是否存在b的首个字符来缩小搜索范围,另一种则是确定复制次数的上下界。
524

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



