1,题目要求
Given two strings A and B, find the minimum number of times A has to be repeated such that B is a substring of it. If no such solution, return -1.
For example, with A = “abcd” and B = “cdabcdab”.
Return 3, because by repeating A three times (“abcdabcdabcd”), B is a substring of it; and B is not a substring of A repeated two times (“abcdabcd”).
给出两个字符串A和B,判断A需要重复几次,使得B成为A的子串。
2,题目思路
首先,对于这个问题,个人想到的是利用字符串前拼接,然后构成一个新串,判断是否是前后满足:
例如对于cdabcdab,两个字符串相连,可以构成:
cdabcdabcdabcdab,可以看到这样的拼接可以在中间构成一个新的字符串。
但是这种做法不可行,因为B的最前方和最后方未必能构成A(在本题的环境下)。
因此,另外一种办法是,首先,设置i代表每次循环开始,A开始的位置(设想”abcd”、”cdabcd”, 只有i=2才有可能比对成功。如果B确实是能够由A全部构成的,则利用一个j来对B遍历,最后j一定是B的长度。最后还需要进行一次余数判断,以此来确定需要多少个A才能构成B。
还有两种比较好的方法,见源码。
3,程序源码
方法1:
class Solution {
public:
int repeatedStringMatch(string A, string B) {
for(auto i = 0, j = 0;i<A.size();i++)
{
for(j = 0;j<B.size() && A[(i+j)%A.size()] == B[j];j++);//确定B是否可以由A构成
if(j == B.size())//此时 i 为 A 开始比对的位置,j显然是B的长度
if((i+j)%A.size() == 0)//A="abcd", B="cdabcdab", 则i=2, j=B.size()=8,可以发现刚好补上了前面的值,所以只需要判断是否有余数即可
return (i+j)/A.size();
else
return (i+j)/A.size()+1;
}
return -1;
}
};
方法2:
class Solution {
public:
int repeatedStringMatch(string A, string B) {
//原理跟上面类似,但是在找B的开始时所用的方法有所不同
string tmp = A + A;
size_t pos = tmp.find(B.substr(0, A.size()));
if(pos == string::npos)
return -1;
int count = 1;
size_t i = 0;
while(i < B.size()) {
if(pos == A.size()) {
pos = 0;
++count;
}
if(A[pos++] != B[i++])
return -1;
}
return count;
}
};
方法3:
class Solution {
public:
int repeatedStringMatch(string A, string B) {
int res = 1;
string tmp = A;
while (tmp.size() < B.size()) {
tmp += A;
res++;
}
if (tmp.find(B) != -1) return res;
tmp += A, res++;
if (tmp.find(B) != -1) return res;
return -1;
}
};
注:
size_t有点像unsigned int,但size_t和unsigned int有所不同,size_t的取值range是目标平台下最大可能的数组尺寸,一些平台下size_t的范围小于int的正数范围,又或者大于unsigned int。