466. Count The Repetitions
DefineS = [s,n]
as the string S which consists of n connected strings s. For example,["abc", 3]
="abcabcabc".
On the other hand, we define that string s1 can be obtained from string s2 if we can remove some characters from s2 such that it becomes s1. For example, “abc” can be obtained from “abdbec” based on our definition, but it can not be obtained from “acbbe”.
You are given two non-empty strings s1 and s2 (each at most 100 characters long) and two integers 0 ≤ n1 ≤ 10^6and 1 ≤ n2 ≤ 10^6. Now consider the strings S1 and S2, whereS1=[s1,n1]
andS2=[s2,n2]
. Find the maximum integer M such that[S2,M]
can be obtained fromS1
.
Example:
Input:
s1="acb", n1=4
s2="ab", n2=2
Return:
2
Discussion
Method
LeetCode
The key is, we just need to calculatewhat will remain after s1 obtains s2.
That is,(s1, s2) -> (sRemain, matchCnt)
; for example,(abcd, ab) -> (cd, 1)
(ababa, ab) -> (a, 2)
(a, aaaa) -> (a, 0)
(aabaabaab, aba) -> (ab, 2)
asaabaaba
exactly matchesaba
twice.
And, each time we appends1
to theremain string
, to make a sequence: (Using[]
to mark theremain string
)(abcd, ab): abcd -> [cd]abcd -> [cd]abcd -> [cd]abcd -> ...
(ababa, ab): ababa -> [a]ababa -> [a]ababa -> [a]ababa -> ...
(a, aaaa): a -> [a]a -> [aa]a -> [aaa]a -> a -> [a]a -> [aa]a -> ...
(aabaabaab, aba): aabaabaab -> [ab]aabaabaab -> [ab]aabaabaab -> ...
Obviously, there will be a loop in the sequence, assume the length of loop isloop
, and the length before the loop isk
.(abcd, ab): loop=1, k=1
(a, aaaa): loop=4, k=0
(aabaabaab, aba): loop=1, k=1
So, we just need to calculatethe count of each loop
, andthe count before entering the loop
, and calculate the total.
public class Solution {
public int getMaxRepetitions(String s1, int n1, String s2, int n2) {
if (!ableToObtain(s1, s2)) return 0; // check if [s1. ∞] obtains s2
int cnt=0, k=-1;
String s=s1;
StringBuilder remainBuilder; // record `remain string`
ArrayList<String> stringList=new ArrayList<>(); // record all the `remain string`
ArrayList<Integer> countList=new ArrayList<>(); // record matching count from start to the current remain string
stringList.add(""); // record empty string
countList.add(0);
for (int i=0;i<=n1;i++) {
remainBuilder=new StringBuilder();
cnt+=getRemain(s, s2, remainBuilder); // get the next remain string, returns the count of matching
String remain=remainBuilder.toString();
if ((k=stringList.indexOf(remain))!=-1) break; // if there is a loop, break
stringList.add(remain); // record the remain string into arraylist
countList.add(cnt);
s=remain+s1; // append s1 to make a new string
}
// here, k is the beginning of the loop
if (k==-1) return cnt/n2; // if there is no loop
int countOfLoop=cnt-countList.get(k), loopLength=stringList.size()-k; // get matching count in the loop, and loop length
cnt=countList.get(k);
n1-=k;
cnt+=countOfLoop*(n1/loopLength);
n1%=loopLength;
cnt+=countList.get(k+n1)-countList.get(k);
return cnt/n2;
}
// check if [s1. ∞] obtains s2
private boolean ableToObtain(String s1, String s2) {
boolean[] cnt=new boolean[26];
for (char c: s1.toCharArray()) cnt[c-'a']=true;
for (char c: s2.toCharArray()) {
if (!cnt[c-'a']) return false;
}
return true;
}
// get remain string after s1 obtains s2, return the matching count
private int getRemain(String s1, String s2, StringBuilder remain) {
int cnt=0, lastMatch=-1, p2=0;
for (int p1=0;p1<s1.length();p1++) {
if (s1.charAt(p1)==s2.charAt(p2)) {
if (++p2==s2.length()) {
p2=0;
cnt++;
lastMatch=p1;
}
}
}
remain.append(s1.substring(lastMatch+1));
return cnt;
}
}
Method 1.2
Optimized
class Solution {
public:
int getMaxRepetitions(string s1, int n1, string s2, int n2) {
vector<int> repeatCount(s2.size() + 1, 0);
vector<int> nextIndex(s2.size() + 1, 0);
int j = 0, cnt = 0;
for (int k = 1; k <= n1; ++k) {
for (int i = 0; i < s1.size(); ++i) {
if (s1[i] == s2[j]) {
++j;
if (j == s2.size()) {
j = 0;
++cnt;
}
}
}
repeatCount[k] = cnt;
nextIndex[k] = j;
for (int start = 0; start < k; ++start) {
if (nextIndex[start] == j) {
int prefixCount = repeatCount[start];
int patternCount = (repeatCount[k] - repeatCount[start]) * (n1 - start) / (k - start);
int suffixCount = repeatCount[start + (n1 - start) % (k - start)] - repeatCount[start];
return (prefixCount + patternCount + suffixCount) / n2;
}
}
}
return repeatCount[n1] / n2;
}
};