Facebook Pixel

1566. Detect Pattern of Length M Repeated K or More Times

EasyArrayEnumeration
Leetcode Link

Problem Description

You are given an array of positive integers arr and need to determine if there exists a pattern of length m that repeats at least k times consecutively.

A pattern is defined as a subarray (consecutive elements) that repeats multiple times in succession without any gaps or overlaps. The pattern has a specific length m and must appear consecutively at least k times.

For example:

  • In array [1, 2, 1, 2, 1, 3] with m = 2 and k = 2, the pattern [1, 2] appears twice consecutively starting at index 0, so it returns true.
  • In array [1, 2, 3, 1, 2] with m = 2 and k = 2, although [1, 2] appears twice, they are not consecutive (there's a 3 in between), so it returns false.

The function should return true if such a pattern exists, otherwise return false.

The key insight is that for a pattern of length m to repeat k times, we need m × k consecutive elements where each element at position i equals the element at position i - m. This means each element matches the corresponding element from the previous pattern repetition.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key observation is that if a pattern of length m repeats k times consecutively, then elements that are exactly m positions apart must be equal.

Think about it this way: if we have a repeating pattern like [a, b, c, a, b, c, a, b, c] where the pattern [a, b, c] (length 3) repeats 3 times, then:

  • Element at index 0 (a) equals element at index 3 (a)
  • Element at index 1 (b) equals element at index 4 (b)
  • Element at index 2 (c) equals element at index 5 (c)
  • And so on...

This means each element should match the element that's exactly m positions before it (except for the first m elements which form the initial pattern).

To detect k consecutive repetitions of a pattern of length m, we need to find (k-1) × m consecutive matches. Why (k-1) × m and not k × m? Because:

  • The first occurrence of the pattern takes up m elements
  • Each additional repetition requires m more matching elements
  • So for k total repetitions, we need the first m elements plus (k-1) × m matching elements

We can track this by maintaining a counter that increments each time we find arr[i] == arr[i-m]. When this counter reaches (k-1) × m, we've found our pattern. If at any point arr[i] != arr[i-m], the pattern is broken and we reset the counter to 0, as we need consecutive matches for a valid repeating pattern.

Solution Approach

The implementation follows a single-pass traversal approach with early termination optimization:

1. Initial Check: First, we verify if the array has enough elements to potentially contain the pattern. If len(arr) < m * k, it's impossible to have a pattern of length m repeating k times, so we return false immediately.

2. Setting up Variables:

  • cnt: A counter to track consecutive matches between elements that are m positions apart
  • target = (k - 1) * m: The number of consecutive matches we need to confirm k repetitions of a pattern of length m

3. Main Traversal: Starting from index m (since we need to compare with elements m positions back), we iterate through the array:

for i in range(m, len(arr)):
    if arr[i] == arr[i - m]:
        cnt += 1
        if cnt == target:
            return True
    else:
        cnt = 0

For each element at position i:

  • If arr[i] == arr[i - m]: This means the current element matches the element m positions before it, indicating the pattern might be continuing. We increment cnt.

    • If cnt reaches target, we've found (k-1) * m consecutive matches, confirming k repetitions of a pattern of length m, so we return true.
  • If arr[i] != arr[i - m]: The pattern is broken at this position. We reset cnt to 0 and continue looking for a new potential pattern.

4. Final Return: If we complete the traversal without finding the required pattern, we return false.

The algorithm runs in O(n) time complexity where n is the length of the array, and uses O(1) extra space, making it highly efficient.

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 the algorithm with a concrete example to see how it detects repeating patterns.

Example: arr = [2, 7, 2, 7, 2, 7, 5], m = 2, k = 3

We're looking for a pattern of length 2 that repeats 3 times consecutively.

Step 1: Initial Setup

  • Array length: 7
  • Check if possible: 7 >= 2 * 3 = 6 ✓ (enough elements)
  • Initialize cnt = 0
  • Calculate target = (3 - 1) * 2 = 4 (we need 4 consecutive matches)

Step 2: Traverse Starting from Index m=2

iarr[i]arr[i-2]Match?cntAction
2221Increment cnt
3772Increment cnt
4223Increment cnt
5774cnt == target, return true

Pattern Found! The pattern [2, 7] repeats 3 times consecutively:

  • First occurrence: indices 0-1: [2, 7]
  • Second occurrence: indices 2-3: [2, 7]
  • Third occurrence: indices 4-5: [2, 7]

Counter-Example: arr = [2, 7, 2, 5, 2, 7], m = 2, k = 3

Same setup: cnt = 0, target = 4

iarr[i]arr[i-2]Match?cntAction
2221Increment cnt
3570Reset cnt to 0
4221Increment cnt
5750Reset cnt to 0

No Pattern Found! Although [2, 7] appears twice, the pattern breaks at index 3 where we have 5 instead of 7. The algorithm correctly returns false because we never reach the target of 4 consecutive matches.

Solution Implementation

1class Solution:
2    def containsPattern(self, arr: List[int], m: int, k: int) -> bool:
3        """
4        Check if array contains a pattern of length m repeated k times consecutively.
5      
6        Args:
7            arr: Input array of integers
8            m: Length of the pattern
9            k: Number of times the pattern should repeat
10      
11        Returns:
12            True if pattern exists, False otherwise
13        """
14        # Early return if array is too small to contain the pattern
15        if len(arr) < m * k:
16            return False
17      
18        # Initialize counter for consecutive matches and calculate target matches needed
19        consecutive_matches = 0
20        # We need (k-1)*m matches because if we have k repetitions of pattern of length m,
21        # there are (k-1)*m positions where arr[i] == arr[i-m]
22        target_matches = (k - 1) * m
23      
24        # Start from index m and compare each element with element m positions before
25        for i in range(m, len(arr)):
26            if arr[i] == arr[i - m]:
27                # Elements match the pattern, increment counter
28                consecutive_matches += 1
29              
30                # Check if we've found enough consecutive matches
31                if consecutive_matches == target_matches:
32                    return True
33            else:
34                # Pattern broken, reset counter
35                consecutive_matches = 0
36      
37        # No valid pattern found
38        return False
39
1class Solution {
2    /**
3     * Checks if the array contains a pattern of length m repeated k consecutive times.
4     * 
5     * @param arr the input array to check for patterns
6     * @param m the length of the pattern
7     * @param k the number of times the pattern should repeat consecutively
8     * @return true if such a pattern exists, false otherwise
9     */
10    public boolean containsPattern(int[] arr, int m, int k) {
11        // Early return if array is too small to contain the required pattern
12        if (arr.length < m * k) {
13            return false;
14        }
15      
16        // Counter for consecutive matching elements at distance m
17        int consecutiveMatches = 0;
18      
19        // Target number of consecutive matches needed to confirm pattern
20        // We need (k-1)*m matches because k repetitions of length m pattern
21        // requires (k-1)*m consecutive position matches
22        int targetMatches = (k - 1) * m;
23      
24        // Iterate through array starting from index m
25        for (int i = m; i < arr.length; i++) {
26            // Check if current element matches the element m positions before
27            if (arr[i] == arr[i - m]) {
28                // Increment counter for consecutive matches
29                consecutiveMatches++;
30              
31                // Check if we've found enough consecutive matches
32                if (consecutiveMatches == targetMatches) {
33                    return true;
34                }
35            } else {
36                // Reset counter if pattern breaks
37                consecutiveMatches = 0;
38            }
39        }
40      
41        // No valid pattern found
42        return false;
43    }
44}
45
1class Solution {
2public:
3    bool containsPattern(vector<int>& arr, int m, int k) {
4        // Early return if array is too small to contain the pattern
5        if (arr.size() < m * k) {
6            return false;
7        }
8      
9        // Initialize counter for consecutive matching elements
10        int consecutiveMatches = 0;
11      
12        // Calculate the target number of consecutive matches needed
13        // We need (k-1) complete patterns worth of matches
14        int targetMatches = (k - 1) * m;
15      
16        // Iterate through array starting from index m
17        for (int i = m; i < arr.size(); ++i) {
18            // Check if current element matches the element m positions back
19            if (arr[i] == arr[i - m]) {
20                // Increment counter for consecutive matches
21                consecutiveMatches++;
22              
23                // If we've reached the target, pattern exists
24                if (consecutiveMatches == targetMatches) {
25                    return true;
26                }
27            } else {
28                // Reset counter if pattern breaks
29                consecutiveMatches = 0;
30            }
31        }
32      
33        // No valid pattern found
34        return false;
35    }
36};
37
1/**
2 * Checks if the array contains a pattern of length m repeated k consecutive times
3 * @param arr - The input array of numbers to check
4 * @param m - The length of the pattern to find
5 * @param k - The number of consecutive times the pattern should repeat
6 * @returns true if pattern exists, false otherwise
7 */
8function containsPattern(arr: number[], m: number, k: number): boolean {
9    // Early return if array is too small to contain the pattern
10    if (arr.length < m * k) {
11        return false;
12    }
13  
14    // Calculate the target number of consecutive matches needed
15    // We need (k-1) * m matches because k repetitions of pattern length m
16    // requires (k-1) * m consecutive matching elements
17    const targetMatchCount: number = (k - 1) * m;
18  
19    // Counter for consecutive matching elements
20    let consecutiveMatches: number = 0;
21  
22    // Start from index m and compare with elements m positions back
23    for (let i: number = m; i < arr.length; i++) {
24        // Check if current element matches the element m positions before
25        if (arr[i] === arr[i - m]) {
26            // Increment counter and check if we've found enough matches
27            consecutiveMatches++;
28            if (consecutiveMatches === targetMatchCount) {
29                return true;
30            }
31        } else {
32            // Reset counter if pattern is broken
33            consecutiveMatches = 0;
34        }
35    }
36  
37    return false;
38}
39

Time and Space Complexity

The time complexity is O(n), where n is the length of the array arr. The algorithm iterates through the array once starting from index m to the end of the array. Each iteration performs constant time operations: comparing two array elements (arr[i] == arr[i - m]), incrementing or resetting a counter, and checking if the counter equals the target value. Since we traverse the array once with constant operations per element, the overall time complexity is linear.

The space complexity is O(1). The algorithm only uses a fixed amount of extra space regardless of the input size. It maintains three variables: cnt (counter), target (calculated as (k - 1) * m), and the loop variable i. These variables occupy constant space that doesn't scale with the input array size, resulting in constant space complexity.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Misunderstanding the Target Calculation

Pitfall: A common mistake is incorrectly calculating how many consecutive matches are needed. Some might think we need k * m matches instead of (k - 1) * m.

Why it happens: The confusion arises from thinking about total elements versus transitions between patterns. If we have k repetitions of a pattern of length m, there are k * m total elements, but only (k - 1) * m positions where we compare elements that are m positions apart.

Example: For pattern [1, 2] repeated 3 times: [1, 2, 1, 2, 1, 2]

  • Total elements: 3 × 2 = 6
  • Comparisons: arr[2]==arr[0], arr[3]==arr[1], arr[4]==arr[2], arr[5]==arr[3] → 4 matches = (3-1) × 2

Solution: Remember that we're counting transitions, not total elements. The formula (k - 1) * m represents the number of "links" between k consecutive patterns.

2. Not Resetting the Counter Properly

Pitfall: Forgetting to reset the counter to 0 when a mismatch occurs, or incorrectly trying to preserve partial matches.

Wrong approach:

if arr[i] != arr[i - m]:
    consecutive_matches -= 1  # Wrong! Should reset to 0

Why it's wrong: Pattern matching requires ALL elements to match consecutively. A single mismatch means we need to start fresh. There's no concept of "partial credit" in this problem.

Solution: Always reset to 0 on mismatch. The pattern must be perfectly consecutive without any breaks.

3. Off-by-One Error in Loop Starting Point

Pitfall: Starting the loop from the wrong index, such as range(0, len(arr)) or range(m-1, len(arr)).

Why it happens: Confusion about when we can first make a comparison. We need at least m elements before we can compare with an element m positions back.

Correct approach: Start from index m because:

  • At index m, we can first compare arr[m] with arr[0]
  • This gives us access to elements from both the potential first and second pattern occurrences

Solution: Always start the loop at index m: for i in range(m, len(arr))

4. Incorrect Early Termination Check

Pitfall: Using the wrong condition for the array size check, such as len(arr) <= m * k or len(arr) < m + k.

Why it's wrong:

  • len(arr) <= m * k would reject valid cases where length exactly equals m * k
  • len(arr) < m + k uses addition instead of multiplication, which is mathematically incorrect

Solution: Use len(arr) < m * k because we need exactly m * k elements to have k complete repetitions of a pattern of length m.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

What does the following code do?

1def f(arr1, arr2):
2  i, j = 0, 0
3  new_arr = []
4  while i < len(arr1) and j < len(arr2):
5      if arr1[i] < arr2[j]:
6          new_arr.append(arr1[i])
7          i += 1
8      else:
9          new_arr.append(arr2[j])
10          j += 1
11  new_arr.extend(arr1[i:])
12  new_arr.extend(arr2[j:])
13  return new_arr
14
1public static List<Integer> f(int[] arr1, int[] arr2) {
2  int i = 0, j = 0;
3  List<Integer> newArr = new ArrayList<>();
4
5  while (i < arr1.length && j < arr2.length) {
6      if (arr1[i] < arr2[j]) {
7          newArr.add(arr1[i]);
8          i++;
9      } else {
10          newArr.add(arr2[j]);
11          j++;
12      }
13  }
14
15  while (i < arr1.length) {
16      newArr.add(arr1[i]);
17      i++;
18  }
19
20  while (j < arr2.length) {
21      newArr.add(arr2[j]);
22      j++;
23  }
24
25  return newArr;
26}
27
1function f(arr1, arr2) {
2  let i = 0, j = 0;
3  let newArr = [];
4  
5  while (i < arr1.length && j < arr2.length) {
6      if (arr1[i] < arr2[j]) {
7          newArr.push(arr1[i]);
8          i++;
9      } else {
10          newArr.push(arr2[j]);
11          j++;
12      }
13  }
14  
15  while (i < arr1.length) {
16      newArr.push(arr1[i]);
17      i++;
18  }
19  
20  while (j < arr2.length) {
21      newArr.push(arr2[j]);
22      j++;
23  }
24  
25  return newArr;
26}
27

Recommended Readings

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

Load More