Taro Logo

Uncrossed Lines

Medium
4 views
2 months ago

You are given two integer arrays nums1 and nums2. We write the integers of nums1 and nums2 (in the order they are given) on two separate horizontal lines.

We may draw connecting lines: a straight line connecting two numbers nums1[i] and nums2[j] such that:

  • nums1[i] == nums2[j], and
  • the line we draw does not intersect any other connecting (non-horizontal) line.

Note that a connecting line cannot intersect even at the endpoints (i.e., each number can only belong to one connecting line).

Return the maximum number of connecting lines we can draw in this way.

Example 1:

nums1 = [1,4,2], nums2 = [1,2,4]

Output: 2

We can draw 2 uncrossed lines as in the diagram. We cannot draw 3 uncrossed lines, because the line from nums1[1] = 4 to nums2[2] = 4 will intersect the line from nums1[2]=2 to nums2[1]=2.

Example 2:

nums1 = [2,5,1,2,5], nums2 = [10,5,2,1,5,2]

Output: 3

Example 3:

nums1 = [1,3,7,1,7,5], nums2 = [1,9,2,5,1]

Output: 2

Constraints:

  • 1 <= nums1.length, nums2.length <= 500
  • 1 <= nums1[i], nums2[j] <= 2000
Sample Answer

Problem Explanation

The problem asks us to find the maximum number of non-intersecting lines that can be drawn between two integer arrays, nums1 and nums2. A line can be drawn between nums1[i] and nums2[j] if nums1[i] == nums2[j], and no two lines can intersect. This problem can be solved using dynamic programming by recognizing it as a variation of the Longest Common Subsequence (LCS) problem.

Brute Force (Inefficient)

We could try all possible combinations of lines, checking for intersections, and keeping track of the maximum number of non-intersecting lines found. This approach would be extremely inefficient due to the exponential number of combinations that need to be checked.

Optimal Solution: Dynamic Programming

We can solve this problem efficiently using dynamic programming. Let dp[i][j] represent the maximum number of connecting lines we can draw between nums1[0...i] and nums2[0...j]. The base case is dp[0][j] = 0 and dp[i][0] = 0 for all i and j. The recurrence relation is as follows:

  • If nums1[i] == nums2[j], then dp[i][j] = dp[i-1][j-1] + 1 (we can draw a line).
  • If nums1[i] != nums2[j], then dp[i][j] = max(dp[i-1][j], dp[i][j-1]) (we either skip nums1[i] or nums2[j]).

By filling the dp table in a bottom-up manner, we can find the maximum number of connecting lines at dp[nums1.length][nums2.length].

def maxUncrossedLines(nums1, nums2):
    n1 = len(nums1)
    n2 = len(nums2)

    dp = [[0] * (n2 + 1) for _ in range(n1 + 1)]

    for i in range(1, n1 + 1):
        for j in range(1, n2 + 1):
            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])

    return dp[n1][n2]

# Example usage:
nums1 = [1,4,2]
nums2 = [1,2,4]
print(maxUncrossedLines(nums1, nums2))  # Output: 2

nums1 = [2,5,1,2,5]
nums2 = [10,5,2,1,5,2]
print(maxUncrossedLines(nums1, nums2))  # Output: 3

nums1 = [1,3,7,1,7,5]
nums2 = [1,9,2,5,1]
print(maxUncrossedLines(nums1, nums2))  # Output: 2

Big(O) Time Complexity Analysis

The time complexity is O(m * n), where 'm' is the length of nums1 and 'n' is the length of nums2. This is because we iterate through each cell of the dp table, which has dimensions (m+1) x (n+1).

Big(O) Space Complexity Analysis

The space complexity is O(m * n) because we use a 2D array dp of size (m+1) x (n+1) to store the intermediate results. The space used by the dp table dominates the space complexity.

Edge Cases

  1. Empty Arrays: If either nums1 or nums2 is empty, the result will be 0, which is handled correctly by the base cases in the dynamic programming approach.
  2. No Matching Numbers: If there are no matching numbers between nums1 and nums2, the result will be 0, which will be correctly computed because the dp table will remain filled with 0s.
  3. Duplicate Numbers: The algorithm handles duplicate numbers correctly by considering all possible matches and choosing the optimal ones to maximize the number of non-intersecting lines.
  4. Large Input: The problem constraints (array lengths up to 500) are reasonable, so stack overflow or excessive memory consumption should not be major concerns. However, if input arrays were significantly larger, space optimization techniques like rolling arrays could be used to reduce space complexity from O(m*n) to O(min(m,n)).