Facebook Pixel

718. Maximum Length of Repeated Subarray

Problem Description

You are given two integer arrays nums1 and nums2. Your task is to find the maximum length of a subarray that appears in both arrays.

A subarray is a contiguous sequence of elements within an array. For example, if nums1 = [1,2,3,4], then [2,3] is a subarray of nums1.

The problem asks you to find the longest common subarray that exists in both nums1 and nums2. The subarray must be exactly the same in both arrays (same elements in the same order) and must be contiguous.

For example:

  • If nums1 = [1,2,3,2,1] and nums2 = [3,2,1,4,7], the longest common subarray is [3,2,1] with length 3
  • If nums1 = [0,0,0,0,0] and nums2 = [0,0,0,0,0], the longest common subarray is [0,0,0,0,0] with length 5

The solution uses dynamic programming where f[i][j] represents the length of the longest common subarray ending at position i-1 in nums1 and position j-1 in nums2. When nums1[i-1] == nums2[j-1], we extend the previous common subarray by 1, otherwise the length is 0. The answer is the maximum value found in the entire DP table.

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

Intuition

The key insight is recognizing that this is a classic dynamic programming problem similar to finding the longest common substring between two strings.

When we look for common subarrays, we need to track contiguous sequences. If we find matching elements at positions i and j in the two arrays, we want to know: can we extend a previous common subarray that ended just before these positions?

This leads us to think about building up solutions from smaller subproblems. If nums1[i] == nums2[j], and we already know the length of the longest common subarray ending at nums1[i-1] and nums2[j-1], then we can extend that length by 1.

The dynamic programming approach emerges naturally from this observation:

  • If elements match at positions i and j, the length of common subarray ending here is 1 + length of common subarray ending at (i-1, j-1)
  • If elements don't match, we can't have a common subarray ending at these positions, so the length is 0

We create a 2D table f[i][j] where each cell represents the length of the longest common subarray ending exactly at position i-1 in nums1 and j-1 in nums2. By computing all possible ending positions and keeping track of the maximum length found, we get our answer.

The reason we use indices i-1 and j-1 instead of i and j directly is to handle the base case cleanly - when there's no previous element, the DP table has 0s at the boundaries, which correctly represents that there's no common subarray to extend from.

Learn more about Binary Search, Dynamic Programming and Sliding Window patterns.

Solution Approach

The solution implements a bottom-up dynamic programming approach using a 2D table to find the maximum length of common subarrays.

Data Structure:

  • A 2D DP table f of size (m+1) × (n+1) where m = len(nums1) and n = len(nums2)
  • Each cell f[i][j] stores the length of the longest common subarray ending at nums1[i-1] and nums2[j-1]

Algorithm Steps:

  1. Initialize the DP table: Create a 2D array f with dimensions (m+1) × (n+1) filled with zeros. The extra row and column handle the base cases where we have empty subarrays.

  2. Fill the DP table: Iterate through each position in both arrays:

    for i in range(1, m + 1):
        for j in range(1, n + 1):
  3. Check for matching elements: At each position (i, j), compare nums1[i-1] with nums2[j-1]:

    • If they match: f[i][j] = f[i-1][j-1] + 1
      • This extends the common subarray that ended at the previous positions
    • If they don't match: f[i][j] remains 0 (already initialized)
      • No common subarray can end at these mismatched positions
  4. Track the maximum: After each update where elements match, update the answer:

    ans = max(ans, f[i][j])
  5. Return the result: The variable ans holds the maximum length found across all possible ending positions.

Time Complexity: O(m × n) where m and n are the lengths of the two arrays, as we fill each cell of the DP table once.

Space Complexity: O(m × n) for the 2D DP table.

The beauty of this approach is that it systematically considers all possible ending positions for common subarrays and builds up the solution incrementally, ensuring we find the global maximum.

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 small example with nums1 = [1,2,3,2,1] and nums2 = [3,2,1,4].

Step 1: Initialize the DP table We create a table f of size (6 × 5) filled with zeros. The indices represent:

  • Rows 0-5 for nums1 (with row 0 as padding)
  • Columns 0-4 for nums2 (with column 0 as padding)

Initial table:

    0  1  2  3  4
    -  3  2  1  4
0 - 0  0  0  0  0
1 1 0  0  0  0  0
2 2 0  0  0  0  0
3 3 0  0  0  0  0
4 2 0  0  0  0  0
5 1 0  0  0  0  0

Step 2: Fill the table row by row

For i=1, j=1: Compare nums1[0]=1 with nums2[0]=3 → No match, f[1][1]=0

For i=1, j=2: Compare nums1[0]=1 with nums2[1]=2 → No match, f[1][2]=0

For i=1, j=3: Compare nums1[0]=1 with nums2[2]=1Match! f[1][3]=f[0][2]+1=1, ans=1

Continuing this process for all cells:

When i=3, j=1: nums1[2]=3 matches nums2[0]=3f[3][1]=f[2][0]+1=1

When i=4, j=2: nums1[3]=2 matches nums2[1]=2f[4][2]=f[3][1]+1=2, ans=2

When i=5, j=3: nums1[4]=1 matches nums2[2]=1f[5][3]=f[4][2]+1=3, ans=3

Final DP table:

    0  1  2  3  4
    -  3  2  1  4
0 - 0  0  0  0  0
1 1 0  0  0  1  0
2 2 0  0  1  0  0
3 3 0  1  0  0  0
4 2 0  0  2  0  0
5 1 0  0  0  3  0

Step 3: Result The maximum value in the table is 3, which corresponds to the common subarray [3,2,1]:

  • In nums1: positions 2,3,4 → [3,2,1]
  • In nums2: positions 0,1,2 → [3,2,1]

The key insight: f[5][3]=3 tells us there's a common subarray of length 3 ending at nums1[4] and nums2[2]. By tracing back diagonally (from f[5][3] to f[4][2] to f[3][1]), we can see how the common subarray was built up incrementally.

Solution Implementation

1class Solution:
2    def findLength(self, nums1: List[int], nums2: List[int]) -> int:
3        """
4        Find the length of the longest common subarray between two arrays.
5      
6        Uses dynamic programming where dp[i][j] represents the length of the
7        longest common subarray ending at nums1[i-1] and nums2[j-1].
8      
9        Args:
10            nums1: First integer array
11            nums2: Second integer array
12          
13        Returns:
14            Length of the longest common subarray
15        """
16        # Get the lengths of both arrays
17        len1, len2 = len(nums1), len(nums2)
18      
19        # Initialize DP table with dimensions (len1+1) x (len2+1)
20        # dp[i][j] stores length of common subarray ending at nums1[i-1] and nums2[j-1]
21        dp = [[0] * (len2 + 1) for _ in range(len1 + 1)]
22      
23        # Track the maximum length found
24        max_length = 0
25      
26        # Iterate through all positions in both arrays
27        for i in range(1, len1 + 1):
28            for j in range(1, len2 + 1):
29                # If elements match, extend the common subarray from previous diagonal
30                if nums1[i - 1] == nums2[j - 1]:
31                    dp[i][j] = dp[i - 1][j - 1] + 1
32                    max_length = max(max_length, dp[i][j])
33                # If elements don't match, common subarray length is 0 (implicit due to initialization)
34      
35        return max_length
36
1class Solution {
2    /**
3     * Find the length of the longest common subarray between two arrays.
4     * Uses dynamic programming to track the longest common subarray ending at each position.
5     * 
6     * @param nums1 First integer array
7     * @param nums2 Second integer array
8     * @return Length of the longest common subarray
9     */
10    public int findLength(int[] nums1, int[] nums2) {
11        int length1 = nums1.length;
12        int length2 = nums2.length;
13      
14        // dp[i][j] represents the length of longest common subarray 
15        // ending at nums1[i-1] and nums2[j-1]
16        int[][] dp = new int[length1 + 1][length2 + 1];
17      
18        int maxLength = 0;
19      
20        // Iterate through all positions in both arrays
21        for (int i = 1; i <= length1; i++) {
22            for (int j = 1; j <= length2; j++) {
23                // If elements match, extend the common subarray from previous position
24                if (nums1[i - 1] == nums2[j - 1]) {
25                    dp[i][j] = dp[i - 1][j - 1] + 1;
26                    // Update the maximum length found so far
27                    maxLength = Math.max(maxLength, dp[i][j]);
28                }
29                // If elements don't match, dp[i][j] remains 0 (default value)
30            }
31        }
32      
33        return maxLength;
34    }
35}
36
1class Solution {
2public:
3    int findLength(vector<int>& nums1, vector<int>& nums2) {
4        // Get the lengths of both input arrays
5        int m = nums1.size();
6        int n = nums2.size();
7      
8        // Create a 2D DP table where dp[i][j] represents the length of 
9        // common subarray ending at nums1[i-1] and nums2[j-1]
10        // Initialize with zeros (default constructor behavior)
11        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
12      
13        // Track the maximum length found so far
14        int maxLength = 0;
15      
16        // Iterate through all possible positions in both arrays
17        for (int i = 1; i <= m; ++i) {
18            for (int j = 1; j <= n; ++j) {
19                // If elements at current positions match
20                if (nums1[i - 1] == nums2[j - 1]) {
21                    // Extend the common subarray length from previous diagonal position
22                    dp[i][j] = dp[i - 1][j - 1] + 1;
23                    // Update the maximum length if current is larger
24                    maxLength = max(maxLength, dp[i][j]);
25                }
26                // If elements don't match, dp[i][j] remains 0 (already initialized)
27            }
28        }
29      
30        // Return the maximum length of common subarray found
31        return maxLength;
32    }
33};
34
1/**
2 * Finds the length of the longest common subarray between two arrays
3 * @param nums1 - First input array
4 * @param nums2 - Second input array
5 * @returns The length of the longest common subarray
6 */
7function findLength(nums1: number[], nums2: number[]): number {
8    // Get the lengths of both arrays
9    const length1: number = nums1.length;
10    const length2: number = nums2.length;
11  
12    // Create a 2D DP table with dimensions (length1 + 1) x (length2 + 1)
13    // dp[i][j] represents the length of common subarray ending at nums1[i-1] and nums2[j-1]
14    const dp: number[][] = Array.from(
15        { length: length1 + 1 }, 
16        () => new Array<number>(length2 + 1).fill(0)
17    );
18  
19    // Track the maximum length found
20    let maxLength: number = 0;
21  
22    // Iterate through all possible positions in both arrays
23    for (let i = 1; i <= length1; i++) {
24        for (let j = 1; j <= length2; j++) {
25            // If elements at current positions match
26            if (nums1[i - 1] === nums2[j - 1]) {
27                // Extend the common subarray length from the previous diagonal position
28                dp[i][j] = dp[i - 1][j - 1] + 1;
29                // Update the maximum length if current subarray is longer
30                maxLength = Math.max(maxLength, dp[i][j]);
31            }
32            // If elements don't match, dp[i][j] remains 0 (already initialized)
33        }
34    }
35  
36    return maxLength;
37}
38

Time and Space Complexity

Time Complexity: O(m * n) where m is the length of nums1 and n is the length of nums2. The algorithm uses two nested loops that iterate through all possible positions in the DP table. The outer loop runs m times (from 1 to m+1), and the inner loop runs n times (from 1 to n+1). Each cell computation takes O(1) time, resulting in a total time complexity of O(m * n).

Space Complexity: O(m * n) where m is the length of nums1 and n is the length of nums2. The algorithm creates a 2D DP table f with dimensions (m+1) × (n+1) to store the lengths of common subarrays ending at each position. This requires O((m+1) * (n+1)) = O(m * n) space. The additional variables ans, i, and j use O(1) space, so the overall space complexity is O(m * n).

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

Common Pitfalls

1. Index Confusion with DP Table Dimensions

One of the most common mistakes is confusing the indexing between the DP table and the original arrays. The DP table has dimensions (len1+1) × (len2+1), but the arrays are indexed from 0 to len-1.

Pitfall Example:

# WRONG: Forgetting to subtract 1 when accessing array elements
if nums1[i] == nums2[j]:  # This will cause IndexError
    dp[i][j] = dp[i-1][j-1] + 1

Correct Approach:

# CORRECT: Remember dp[i][j] corresponds to nums1[i-1] and nums2[j-1]
if nums1[i-1] == nums2[j-1]:
    dp[i][j] = dp[i-1][j-1] + 1

2. Space Optimization Oversight

While the 2D DP solution works correctly, it uses O(m×n) space which can be excessive for large arrays. Since we only need the previous row to compute the current row, we can optimize space.

Space-Optimized Solution:

def findLength(self, nums1: List[int], nums2: List[int]) -> int:
    len1, len2 = len(nums1), len(nums2)
    # Use only two rows instead of full 2D table
    prev = [0] * (len2 + 1)
    curr = [0] * (len2 + 1)
    max_length = 0
  
    for i in range(1, len1 + 1):
        for j in range(1, len2 + 1):
            if nums1[i-1] == nums2[j-1]:
                curr[j] = prev[j-1] + 1
                max_length = max(max_length, curr[j])
            else:
                curr[j] = 0
        prev, curr = curr, prev
  
    return max_length

3. Forgetting to Reset Values When Elements Don't Match

When using space optimization or reusing arrays, failing to reset values when elements don't match can lead to incorrect results.

Pitfall Example:

# WRONG: Not resetting curr[j] when elements don't match
for j in range(1, len2 + 1):
    if nums1[i-1] == nums2[j-1]:
        curr[j] = prev[j-1] + 1
    # Missing: else curr[j] = 0

This leaves old values in curr[j] which can corrupt future calculations.

4. Misunderstanding the Problem - Subarray vs Subsequence

A critical mistake is confusing this problem with the Longest Common Subsequence (LCS) problem. Remember:

  • Subarray: Must be contiguous
  • Subsequence: Can skip elements

Wrong Approach (LCS logic):

# This finds longest common subsequence, NOT subarray
if nums1[i-1] == nums2[j-1]:
    dp[i][j] = dp[i-1][j-1] + 1
else:
    dp[i][j] = max(dp[i-1][j], dp[i][j-1])  # WRONG for subarray problem

For the subarray problem, when elements don't match, the length must be 0, not the maximum of adjacent cells.

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

Consider the classic dynamic programming of longest increasing subsequence:

Find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order.

For example, the length of LIS for [50, 3, 10, 7, 40, 80] is 4 and LIS is [3, 7, 40, 80].

What is the recurrence relation?


Recommended Readings

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

Load More