Facebook Pixel

466. Count The Repetitions

Problem Description

This problem asks you to find how many times a repeated string can be obtained from another repeated string through character removal.

First, let's understand the notation [s, n] which means string s repeated n times. For example, ["abc", 3] gives us "abcabcabc".

The problem defines that string s1 can be "obtained from" string s2 if we can remove some characters from s2 to get s1. For instance, "abc" can be obtained from "ab**dbe**c" by removing the characters 'd', 'b', and 'e'.

Given:

  • Two strings s1 and s2
  • Two integers n1 and n2
  • This creates str1 = [s1, n1] (string s1 repeated n1 times)
  • And str2 = [s2, n2] (string s2 repeated n2 times)

The task is to find the maximum integer m such that [str2, m] (which means str2 repeated m times) can be obtained from str1.

In other words, you need to determine how many complete copies of str2 can be formed by removing characters from str1, where both str1 and str2 are themselves repeated strings.

For example, if s1 = "acb", n1 = 4, s2 = "ab", n2 = 2:

  • str1 = "acbacbacbacb" (repeating "acb" 4 times)
  • str2 = "abab" (repeating "ab" 2 times)
  • From str1, we can obtain multiple copies of str2 by removing appropriate characters
  • The answer would be the maximum number of times str2 can be obtained from str1
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is that when we're matching characters from s1 to form s2, there's a repeating pattern that emerges. Since we're dealing with repeated strings, after processing one complete s1, we'll be at some position in s2. This position and the number of complete s2 strings we've formed create a cycle.

Think about it this way: when we scan through one complete s1, we're essentially asking "starting from position i in s2, how many complete s2 strings can I form, and where will I end up in s2?" Since s2 has a finite length, there are only a limited number of starting positions (0 to len(s2)-1).

The brilliant observation is that we can precompute this information for all possible starting positions in s2. For each starting position i in s2, we can determine:

  • How many complete s2 strings we can form by going through one s1 (let's call this cnt)
  • What position in s2 we'll be at after processing one s1 (let's call this j)

This creates a mapping: d[i] = (cnt, j). This tells us that if we start at position i in s2 and process one complete s1, we'll form cnt complete s2 strings and end up at position j in s2.

Once we have this mapping, simulating the entire process becomes straightforward. We just need to iterate n1 times (for each repetition of s1), and for each iteration, we look up our current position in the precomputed table to find how many s2 strings we formed and where we'll be next.

The final step is dividing by n2 because we're looking for complete str2 strings (which is s2 repeated n2 times), not just complete s2 strings.

This approach transforms what could be a character-by-character simulation of potentially very long strings into a simple iteration with precomputed state transitions.

Solution Approach

The implementation follows a two-phase approach: preprocessing and iteration.

Phase 1: Preprocessing

We create a dictionary d to store the state transitions. For each possible starting position i in s2 (where i ranges from 0 to len(s2)-1), we simulate matching one complete s1:

for i in range(n):  # n is the length of s2
    cnt = 0  # count of complete s2 strings formed
    j = i    # current position in s2
    for c in s1:
        if c == s2[j]:
            j += 1
        if j == n:  # reached the end of s2
            cnt += 1
            j = 0   # wrap around to start of s2
    d[i] = (cnt, j)

For each starting position i, we:

  • Initialize a counter cnt to track complete s2 strings formed
  • Set current position j to i
  • Iterate through each character c in s1:
    • If c matches the current character in s2 at position j, advance j
    • If we've completed s2 (when j == n), increment cnt and reset j to 0
  • Store the result as d[i] = (cnt, j), where cnt is the number of complete s2 strings and j is the final position in s2

Phase 2: Iteration

Now we simulate processing n1 copies of s1:

ans = 0
j = 0  # start at position 0 in s2
for _ in range(n1):
    cnt, j = d[j]  # lookup precomputed values
    ans += cnt     # add complete s2 strings formed

We:

  • Start with position j = 0 in s2
  • For each of the n1 repetitions of s1:
    • Look up d[j] to get the number of complete s2 strings and the next position
    • Add cnt to our running total
    • Update j to the new position for the next iteration

Final Calculation

Since we want complete str2 strings (where str2 = [s2, n2]), we divide the total count of s2 strings by n2:

return ans // n2

This approach has a time complexity of O(|s2| × |s1| + n1) where the first term is for preprocessing and the second for iteration. The space complexity is O(|s2|) for storing the transition table.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a concrete example with s1 = "acb", n1 = 4, s2 = "ab", n2 = 2.

First, we need to understand what we're looking for:

  • str1 = "acbacbacbacb" (repeating "acb" 4 times)
  • str2 = "abab" (repeating "ab" 2 times)
  • We want to find how many complete str2 strings can be obtained from str1

Phase 1: Build the transition table

We'll create a dictionary d where d[i] tells us what happens when we start at position i in s2 and process one complete s1.

For s2 = "ab", we have positions 0 and 1:

Starting at position 0 in s2:

  • We need to match 'a' (at position 0 in s2)
  • Process s1 = "acb":
    • 'a' matches s2[0='a'] → advance to position 1
    • 'c' doesn't match s2[1='b'] → stay at position 1
    • 'b' matches s2[1='b'] → advance to position 2 (which wraps to 0), we completed one s2!
  • Result: d[0] = (1, 0) (completed 1 copy of s2, ended at position 0)

Starting at position 1 in s2:

  • We need to match 'b' (at position 1 in s2)
  • Process s1 = "acb":
    • 'a' doesn't match s2[1='b'] → stay at position 1
    • 'c' doesn't match s2[1='b'] → stay at position 1
    • 'b' matches s2[1='b'] → advance to position 2 (which wraps to 0), we completed one s2!
  • Result: d[1] = (1, 0) (completed 1 copy of s2, ended at position 0)

Phase 2: Simulate n1 iterations

Now we process 4 copies of s1, starting at position 0 in s2:

  • Iteration 1: Start at position 0 → d[0] = (1, 0) → gained 1 s2, now at position 0
  • Iteration 2: Start at position 0 → d[0] = (1, 0) → gained 1 s2, now at position 0
  • Iteration 3: Start at position 0 → d[0] = (1, 0) → gained 1 s2, now at position 0
  • Iteration 4: Start at position 0 → d[0] = (1, 0) → gained 1 s2, now at position 0

Total s2 strings formed: 1 + 1 + 1 + 1 = 4

Final Calculation

We formed 4 complete s2 strings. Since str2 = [s2, 2] (meaning 2 copies of s2), we have:

  • Number of complete str2 strings = 4 // 2 = 2

Therefore, the answer is 2. We can obtain str2 = "abab" exactly 2 times from str1 = "acbacbacbacb".

To verify: From "acbacbacbacb", we can extract:

  • First "abab": acbacbacbacb
  • Second "abab": acbacbacbacb

Solution Implementation

1class Solution:
2    def getMaxRepetitions(self, s1: str, n1: int, s2: str, n2: int) -> int:
3        """
4        Find the maximum number of times str2 = s2 * n2 can be obtained from str1 = s1 * n1.
5      
6        Args:
7            s1: The base string to be repeated n1 times
8            n1: Number of times s1 is repeated
9            s2: The pattern string to be repeated n2 times  
10            n2: Number of times s2 is repeated
11          
12        Returns:
13            Maximum number of str2 that can be obtained from str1
14        """
15        s2_length = len(s2)
16      
17        # Build a transition table for each starting position in s2
18        # Key: starting index in s2
19        # Value: (number of complete s2 cycles, ending index in s2) after processing one s1
20        transition_table = {}
21      
22        for start_index in range(s2_length):
23            complete_cycles = 0
24            current_index = start_index
25          
26            # Process one complete s1 string
27            for char in s1:
28                if char == s2[current_index]:
29                    current_index += 1
30                  
31                # Check if we completed one cycle of s2
32                if current_index == s2_length:
33                    complete_cycles += 1
34                    current_index = 0
35                  
36            transition_table[start_index] = (complete_cycles, current_index)
37      
38        # Simulate processing n1 copies of s1
39        total_s2_cycles = 0
40        current_s2_index = 0
41      
42        for _ in range(n1):
43            # Get transition result from current position
44            cycles_gained, next_index = transition_table[current_s2_index]
45            total_s2_cycles += cycles_gained
46            current_s2_index = next_index
47      
48        # Calculate how many complete str2 (s2 * n2) we can form
49        return total_s2_cycles // n2
50
1class Solution {
2    public int getMaxRepetitions(String s1, int n1, String s2, int n2) {
3        int s1Length = s1.length();
4        int s2Length = s2.length();
5      
6        // dp[i] stores [count, nextIndex] where:
7        // - count: number of complete s2 strings we can match when starting from index i in s2
8        // - nextIndex: the index in s2 where we end up after processing one complete s1
9        int[][] dp = new int[s2Length][2];
10      
11        // Precompute the transition for each possible starting position in s2
12        for (int startIndex = 0; startIndex < s2Length; startIndex++) {
13            int currentS2Index = startIndex;
14            int completeS2Count = 0;
15          
16            // Process one complete s1 string
17            for (int s1Index = 0; s1Index < s1Length; s1Index++) {
18                // If characters match, advance the pointer in s2
19                if (s1.charAt(s1Index) == s2.charAt(currentS2Index)) {
20                    currentS2Index++;
21                  
22                    // If we completed one full s2, reset index and increment count
23                    if (currentS2Index == s2Length) {
24                        currentS2Index = 0;
25                        completeS2Count++;
26                    }
27                }
28            }
29          
30            // Store the result: [number of complete s2 found, ending position in s2]
31            dp[startIndex] = new int[] {completeS2Count, currentS2Index};
32        }
33      
34        // Calculate total number of s2 strings we can obtain from n1 copies of s1
35        int totalS2Count = 0;
36        int currentS2Position = 0;
37      
38        // Process each copy of s1
39        for (int remaining = n1; remaining > 0; remaining--) {
40            // Add the number of complete s2 strings from current position
41            totalS2Count += dp[currentS2Position][0];
42            // Update position for next iteration
43            currentS2Position = dp[currentS2Position][1];
44        }
45      
46        // Return how many complete (s2 * n2) sequences we can form
47        return totalS2Count / n2;
48    }
49}
50
1class Solution {
2public:
3    int getMaxRepetitions(string s1, int n1, string s2, int n2) {
4        int len1 = s1.size();
5        int len2 = s2.size();
6      
7        // For each starting position in s2, precompute:
8        // - How many complete s2 sequences we can match using one s1
9        // - The ending position in s2 after matching through one s1
10        vector<pair<int, int>> transitions;
11      
12        for (int startPos = 0; startPos < len2; ++startPos) {
13            int currentPos = startPos;
14            int completeMatches = 0;
15          
16            // Simulate matching through one complete s1
17            for (int i = 0; i < len1; ++i) {
18                if (s1[i] == s2[currentPos]) {
19                    currentPos++;
20                    // If we completed one s2 sequence
21                    if (currentPos == len2) {
22                        completeMatches++;
23                        currentPos = 0;  // Reset to beginning of s2
24                    }
25                }
26            }
27          
28            // Store the number of complete s2 matches and ending position
29            transitions.emplace_back(completeMatches, currentPos);
30        }
31      
32        // Count total s2 sequences matched across all n1 copies of s1
33        int totalS2Matches = 0;
34        int currentS2Position = 0;  // Starting position in s2
35      
36        for (int iteration = 0; iteration < n1; ++iteration) {
37            // Add matches from this s1 copy based on current s2 position
38            totalS2Matches += transitions[currentS2Position].first;
39            // Update position for next s1 copy
40            currentS2Position = transitions[currentS2Position].second;
41        }
42      
43        // Return how many complete [s2, n2] we can form
44        return totalS2Matches / n2;
45    }
46};
47
1/**
2 * Calculates the maximum number of times s2 can be obtained from s1
3 * where s1 is repeated n1 times and s2 is repeated n2 times
4 * @param s1 - The first string
5 * @param n1 - Number of times s1 is repeated
6 * @param s2 - The second string  
7 * @param n2 - Number of times s2 is repeated
8 * @returns Maximum repetitions of s2*n2 that can be obtained from s1*n1
9 */
10function getMaxRepetitions(s1: string, n1: number, s2: string, n2: number): number {
11    const s2Length: number = s2.length;
12  
13    // Create a 2D array to store state transitions
14    // transitions[i][0]: number of complete s2 strings found when starting from index i of s2
15    // transitions[i][1]: ending position in s2 after processing one complete s1
16    const transitions: number[][] = Array.from(
17        { length: s2Length }, 
18        () => [0, 0]
19    );
20  
21    // Precompute transitions for each starting position in s2
22    for (let startIndex: number = 0; startIndex < s2Length; startIndex++) {
23        let currentIndex: number = startIndex;
24        let completeS2Count: number = 0;
25      
26        // Process one complete s1 string
27        for (const char of s1) {
28            if (char === s2[currentIndex]) {
29                currentIndex++;
30              
31                // If we've matched all of s2, reset and increment count
32                if (currentIndex === s2Length) {
33                    currentIndex = 0;
34                    completeS2Count++;
35                }
36            }
37        }
38      
39        // Store the transition result
40        transitions[startIndex] = [completeS2Count, currentIndex];
41    }
42  
43    // Calculate total s2 strings found using the transition table
44    let totalS2Count: number = 0;
45    let currentS2Index: number = 0;
46  
47    // Process n1 repetitions of s1
48    while (n1 > 0) {
49        totalS2Count += transitions[currentS2Index][0];
50        currentS2Index = transitions[currentS2Index][1];
51        n1--;
52    }
53  
54    // Return the number of complete s2*n2 sequences
55    return Math.floor(totalS2Count / n2);
56}
57

Time and Space Complexity

Time Complexity: O(m × n + n₁)

The algorithm consists of two main parts:

  1. Preprocessing phase: Building the dictionary d by iterating through all n possible starting positions in s2. For each starting position i (where i ranges from 0 to n-1), we iterate through all characters in s1 (length m) to count how many complete s2 sequences can be formed. This gives us O(m × n) time complexity for the preprocessing.

  2. Simulation phase: We then iterate n1 times to simulate going through s1 for n1 repetitions. In each iteration, we perform a constant-time lookup in the dictionary d to get the precomputed values (cnt, j). This phase takes O(n₁) time.

Therefore, the total time complexity is O(m × n + n₁), where m = len(s1), n = len(s2), and n₁ is the repetition count for s1.

Space Complexity: O(n)

The algorithm uses a dictionary d to store precomputed values for each possible starting position in s2. Since there are exactly n possible starting positions (indices 0 to n-1), and each entry stores a tuple of two integers (cnt, j), the space complexity is O(n), where n = len(s2).

Common Pitfalls

1. Not Handling Empty or Invalid Input

The code assumes both s1 and s2 contain valid characters and are non-empty. If s2 is empty or n1/n2 are zero, the code will fail with division by zero or other errors.

Solution:

def getMaxRepetitions(self, s1: str, n1: int, s2: str, n2: int) -> int:
    # Add input validation
    if not s1 or not s2 or n1 == 0 or n2 == 0:
        return 0
  
    # Check if s1 contains all characters needed for s2
    if not all(c in s1 for c in set(s2)):
        return 0
  
    # Rest of the implementation...

2. Cycle Detection Optimization Missed

The current solution simulates all n1 iterations linearly, which can be inefficient when n1 is very large. Since the state transitions form a cycle, we could detect and skip the cycle.

Solution:

def getMaxRepetitions(self, s1: str, n1: int, s2: str, n2: int) -> int:
    s2_length = len(s2)
    transition_table = {}
  
    # Build transition table (same as before)
    for start_index in range(s2_length):
        # ... (preprocessing code)
        transition_table[start_index] = (complete_cycles, current_index)
  
    # Detect cycle using Floyd's algorithm or state tracking
    visited = {}
    total_s2_cycles = 0
    current_s2_index = 0
  
    for iteration in range(n1):
        if current_s2_index in visited:
            # Cycle detected
            cycle_start = visited[current_s2_index][0]
            cycle_length = iteration - cycle_start
            cycles_in_cycle = total_s2_cycles - visited[current_s2_index][1]
          
            # Calculate remaining iterations
            remaining = n1 - iteration
            full_cycles = remaining // cycle_length
            remainder = remaining % cycle_length
          
            # Add cycles from full repetitions
            total_s2_cycles += full_cycles * cycles_in_cycle
          
            # Process remainder
            for _ in range(remainder):
                cycles_gained, current_s2_index = transition_table[current_s2_index]
                total_s2_cycles += cycles_gained
          
            return total_s2_cycles // n2
      
        visited[current_s2_index] = (iteration, total_s2_cycles)
        cycles_gained, current_s2_index = transition_table[current_s2_index]
        total_s2_cycles += cycles_gained
  
    return total_s2_cycles // n2

3. Integer Overflow for Large Values

When n1 is very large (up to 10^6), the multiplication and accumulation of cycles could potentially cause issues in languages with fixed integer sizes (though Python handles arbitrary precision integers).

Solution: Early termination when we know we can't form any more complete str2:

def getMaxRepetitions(self, s1: str, n1: int, s2: str, n2: int) -> int:
    # ... (previous code)
  
    # During simulation
    for iteration in range(n1):
        cycles_gained, current_s2_index = transition_table[current_s2_index]
        total_s2_cycles += cycles_gained
      
        # Early termination: if no progress is possible
        if cycles_gained == 0 and current_s2_index == 0:
            # We've completed a full cycle without any matches
            break
  
    return total_s2_cycles // n2
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which two pointer techniques do you use to check if a string is a palindrome?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More