LeetCode 1035. Uncrossed Lines

[Med] LeetCode 1035. Uncrossed Lines

链接: https://leetcode.com/problems/uncrossed-lines/

题目描述:
We write the integers of A and B (in the order they are given) on two separate horizontal lines.

Now, we may draw connecting lines: a straight line connecting two numbers A[i] and B[j] such that:

A[i] == B[j];
The line we draw does not intersect any other connecting (non-horizontal) line.
Note that a connecting lines cannot intersect even at the endpoints: each number can only belong to one connecting line.

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

Example 1:

在这里插入图片描述
Input: A = [1,4,2], B = [1,2,4]
Output: 2
Explanation: We can draw 2 uncrossed lines as in the diagram.
We cannot draw 3 uncrossed lines, because the line from A[1]=4 to B[2]=4 will intersect the line from A[2]=2 to B[1]=2.

Example 2:

Input: A = [2,5,1,2,5], B = [10,5,2,1,5,2]
Output: 3

Example 3:

Input: A = [1,3,7,1,7,5], B = [1,9,2,5,1]
Output: 2

Note:

  • 1 <= A.length <= 500
  • 1 <= B.length <= 500
  • 1 <= A[i], B[i] <= 2000

Tag: DP
解题思路
这道题目挺有意思的,给我们两个数组,让我们给两个数组中相同的元素进行连线,每一个元素最多可以被连一次。同时这些连线不可以交叉,比如说 [1,2,3] 和[3,2,1] 两个数组,当两个数组当中的1都链接在一起之后,2和3就不可以互相连线了。因为这样会导致他们和两边1的连线交叉。同理,如果2或者3和对方连线了,那么其余的也不可以连线了。因为这样他们也交叉了。

一开始我想的办法特别的复杂。因为两边都需要保持不交叉的连线。我就使用了两个指针。这样会有三种不同的情况出现。
(1) 我们选择数组A中的 A[idxA]元素作为基准,然后在数组B当中找到在idxB之后,且位置最小的,和A[idxA]相同的元素。
(2) 以数组B 中的A[idxB]元素作为基准,然后同样的方法看能不能在A中找到符合条件的元素。
(3) A和B中的元素我们都不选,而是直接将两个指针向后移动一位,相当于忽略了这两个元素。

但是后来转念一想,看了一眼自己的草稿。发现实际上这不就是找到两个数组中最长的common subsequence吗?这样既满足了相同的元素,也满足了不交叉的限制。

这样一想那么代码就简单很多了,就是一个典型的DP问题。
我们创建一个二维数组,长宽就是两个数组的长度+1

(1)不管能帮否match上,dp[i][j]等于max(dp[i-1][j], dp[i][j-1])。就是上一次match A中的上一位元素或者上一次match B中上一位元素的较长的那一个。
(2)如果A[i]可以和B[j]对应的话,我们看看在这之前match的,也就是dp[i-1][j-1]+1和当前dp[i][j]比较会不会更长一些。

最后返回dp[m][n]的值。

TIME & SPACE: O(NM)

解法一:

class Solution {
    
    public int maxUncrossedLines(int[] A, int[] B) {
        int m = A.length, n = B.length;
        int[][] dp = new int[m+1][n+1];
        
        for(int i=1; i<=m ; i++){
            for(int j=1; j <= n; j++){
                dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
                if(A[i-1] == B[j-1]){
                    dp[i][j] = Math.max(dp[i-1][j-1]+1, dp[i][j]);
                }
            }
        }
        return dp[m][n];
    

解法二:
我们观察到,每一行都只和上一行有关系。所以我们可以用滚动数组的办法进一步的压缩空间。

class Solution {
    
    public int maxUncrossedLines(int[] A, int[] B) {
        int m = A.length, n = B.length;
        int[] dp = new int[n+1];
        
        for(int i=0; i<m ; i++){
            int prevRowPrevCol = 0;
            int prevRow = 0;
            
            for(int j=0; j < n; j++){
                prevRowPrevCol = prevRow;
                prevRow = dp[j+1];
                dp[j+1] = Math.max(dp[j], prevRow);
                
                if(A[i] == B[j]){
                    dp[j+1] = Math.max(prevRowPrevCol+1, dp[j]);
                }
               
            }
        }
        return dp[n];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值