Problem#
We define str = [s, n]
as the string str
which consists of the string s
concatenated n
times.
For example, str == ["abc", 3] =="abcabcabc"
.
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, s1 = "abc"
can be obtained from s2 = "ab**dbe**c"
based on our definition by removing the bolded underlined characters.
You are given two strings s1
and s2
and two integers n1
and n2
. You have the two strings str1 = [s1, n1]
and str2 = [s2, n2]
.
Return the maximum integer m
such that str = [str2, m]
can be obtained from str1
.
Examples#
Example 1#
1
2
Input: s1 = "acb" , n1 = 4 , s2 = "ab" , n2 = 2
Output: 2
Example 2#
1
2
Input: s1 = "acb" , n1 = 1 , s2 = "acb" , n2 = 1
Output: 1
Constraints#
1 <= s1.length, s2.length <= 100
s1
and s2
consist of lowercase English letters.
1 <= n1, n2 <= 106
Solution#
Method 1 – Cycle Detection and Simulation#
Intuition#
We want to find the maximum number of times str2 (repeated n2 times) can be obtained from str1 (repeated n1 times) by deleting characters. Since n1 and n2 can be large, we use cycle detection to speed up the simulation. By tracking the position in s2 and the count of s2 matches after each s1 block, we can detect cycles and skip redundant work.
Approach#
Simulate matching s2 in s1, counting how many times s2 is matched after each s1 block.
Track the position in s2 and the count of s2 matches for each s1 block in a map.
If a cycle is detected (same s2 position seen before), calculate how many cycles fit in the remaining s1 blocks and skip them.
Continue simulation for the remaining blocks.
Return the total number of s2 matches divided by n2.
Code#
Cpp
Go
Java
Kotlin
Python
Rust
Typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public :
int getMaxRepetitions(string s1, int n1, string s2, int n2) {
int l1 = s1.size(), l2 = s2.size();
vector< int > indexr(l2+ 1 ), countr(l2+ 1 );
int idx = 0 , cnt = 0 ;
for (int k = 1 ; k <= n1; ++ k) {
for (int i = 0 ; i < l1; ++ i) {
if (s1[i] == s2[idx]) {
idx++ ;
if (idx == l2) {
cnt++ ;
idx = 0 ;
}
}
}
if (indexr[idx]) {
int pre = indexr[idx], pre_cnt = countr[idx];
int cycle = (n1 - pre) / (k - pre);
cnt = pre_cnt + cycle * (cnt - pre_cnt);
k = pre + cycle * (k - pre);
}
indexr[idx] = k;
countr[idx] = cnt;
}
return cnt / n2;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
func getMaxRepetitions (s1 string , n1 int , s2 string , n2 int ) int {
l1 , l2 := len(s1 ), len(s2 )
indexr := make([]int , l2 + 1 )
countr := make([]int , l2 + 1 )
idx , cnt := 0 , 0
for k := 1 ; k <= n1 ; k ++ {
for i := 0 ; i < l1 ; i ++ {
if s1 [i ] == s2 [idx ] {
idx ++
if idx == l2 {
cnt ++
idx = 0
}
}
}
if indexr [idx ] > 0 {
pre , pre_cnt := indexr [idx ], countr [idx ]
cycle := (n1 - pre ) / (k - pre )
cnt = pre_cnt + cycle * (cnt - pre_cnt )
k = pre + cycle * (k - pre )
}
indexr [idx ] = k
countr [idx ] = cnt
}
return cnt / n2
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public int getMaxRepetitions (String s1, int n1, String s2, int n2) {
int l1 = s1.length (), l2 = s2.length ();
int [] indexr = new int [ l2+ 1] , countr = new int [ l2+ 1] ;
int idx = 0, cnt = 0;
for (int k = 1; k <= n1; ++ k) {
for (int i = 0; i < l1; ++ i) {
if (s1.charAt (i) == s2.charAt (idx)) {
idx++ ;
if (idx == l2) {
cnt++ ;
idx = 0;
}
}
}
if (indexr[ idx] > 0) {
int pre = indexr[ idx] , pre_cnt = countr[ idx] ;
int cycle = (n1 - pre) / (k - pre);
cnt = pre_cnt + cycle * (cnt - pre_cnt);
k = pre + cycle * (k - pre);
}
indexr[ idx] = k;
countr[ idx] = cnt;
}
return cnt / n2;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
fun getMaxRepetitions (s1: String, n1: Int, s2: String, n2: Int): Int {
val l1 = s1.length; val l2 = s2.length
val indexr = IntArray(l2+1 )
val countr = IntArray(l2+1 )
var idx = 0 ; var cnt = 0
var k = 1
while (k <= n1) {
for (i in 0 until l1) {
if (s1[i] == s2[idx]) {
idx++
if (idx == l2) {
cnt++
idx = 0
}
}
}
if (indexr[idx] > 0 ) {
val pre = indexr[idx]; val pre_cnt = countr[idx]
val cycle = (n1 - pre) / (k - pre)
cnt = pre_cnt + cycle * (cnt - pre_cnt)
k = pre + cycle * (k - pre)
}
indexr[idx] = k
countr[idx] = cnt
k++
}
return cnt / n2
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def getMaxRepetitions (s1: str, n1: int, s2: str, n2: int) -> int:
l1, l2 = len(s1), len(s2)
indexr = [0 ]* (l2+ 1 )
countr = [0 ]* (l2+ 1 )
idx = cnt = 0
k = 1
while k <= n1:
for i in range(l1):
if s1[i] == s2[idx]:
idx += 1
if idx == l2:
cnt += 1
idx = 0
if indexr[idx]:
pre, pre_cnt = indexr[idx], countr[idx]
cycle = (n1 - pre) // (k - pre)
cnt = pre_cnt + cycle * (cnt - pre_cnt)
k = pre + cycle * (k - pre)
indexr[idx] = k
countr[idx] = cnt
k += 1
return cnt // n2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
impl Solution {
pub fn get_max_repetitions (s1: String, n1: i32 , s2: String, n2: i32 ) -> i32 {
let l1 = s1.len(); let l2 = s2.len();
let s1 = s1.as_bytes(); let s2 = s2.as_bytes();
let mut indexr = vec! [0 ; l2+ 1 ];
let mut countr = vec! [0 ; l2+ 1 ];
let mut idx = 0 ; let mut cnt = 0 ;
let mut k = 1 ;
while k <= n1 {
for i in 0 .. l1 {
if s1[i] == s2[idx] {
idx += 1 ;
if idx == l2 {
cnt += 1 ;
idx = 0 ;
}
}
}
if indexr[idx] > 0 {
let pre = indexr[idx]; let pre_cnt = countr[idx];
let cycle = (n1 - pre) / (k - pre);
cnt = pre_cnt + cycle * (cnt - pre_cnt);
k = pre + cycle * (k - pre);
}
indexr[idx] = k;
countr[idx] = cnt;
k += 1 ;
}
cnt / n2
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
getMaxRepetitions (s1 : string , n1 : number , s2 : string , n2 : number ): number {
const l1 = s1 .length , l2 = s2 .length ;
const indexr = Array(l2 + 1 ).fill (0 ), countr = Array(l2 + 1 ).fill (0 );
let idx = 0 , cnt = 0 , k = 1 ;
while (k <= n1 ) {
for (let i = 0 ; i < l1 ; i ++ ) {
if (s1 [i ] === s2 [idx ]) {
idx ++ ;
if (idx === l2 ) {
cnt ++ ;
idx = 0 ;
}
}
}
if (indexr [idx ]) {
const pre = indexr [idx ], pre_cnt = countr [idx ];
const cycle = Math.floor ((n1 - pre ) / (k - pre ));
cnt = pre_cnt + cycle * (cnt - pre_cnt );
k = pre + cycle * (k - pre );
}
indexr [idx ] = k ;
countr [idx ] = cnt ;
k ++ ;
}
return Math.floor (cnt / n2 );
}
}
Complexity#
⏰ Time complexity: O(n1 * len(s1) + len(s2))
, but cycle detection makes it much faster in practice.
🧺 Space complexity: O(len(s2))
, for tracking states.