一、题目

在两条独立的水平线上按给定的顺序写下 nums1 和 nums2 中的整数。

现在,可以绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线,这些直线需要同时满足满足:

nums1[i] == nums2[j]
且绘制的直线不与任何其他连线(非水平线)相交。
请注意,连线即使在端点也不能相交:每个数字只能属于一条连线。

以这种方法绘制线条,并返回可以绘制的最大连线数。

点击查看原题

二、思路

1)暴力法

暴力法的思路主要是通过循环找到所有解中最大的解值,通过两层循环+递归的方式(因为nums1数字就两种状态,连线or不连线),就假定backTrace函数是求出[loc1, nums1.length)与[loc2, nums2.length)的最多不相交线数量。

2)动态规划

暴力法重复计算了后续的连线方式,可以考虑使用动态规划记忆化状态。
本题可以化为求最长公共子序列问题,可以使用一个dp数组,dp[m][n]代表从nums1的[0, m]和nums2的[0, n]区间最多连线数量,那么dp[m][n]是依赖于之前的状态的(dp[m-1][n-1]、dp[m][n-1]、dp[m-1][n]),可以写出如下状态转移方程:
1035. 不相交的线-每日一题 - 图1

三、代码

1)暴力法

  1. class Solution {
  2. private int[] nums1;
  3. private int[] nums2;
  4. public int maxUncrossedLines(int[] nums1, int[] nums2) {
  5. this.nums1 = nums1;
  6. this.nums2 = nums2;
  7. return backTrace(0, 0);
  8. }
  9. public int backTrace(int loc1, int loc2) {
  10. int ans = 0;
  11. for (int i = loc1; i < nums1.length; i++) {
  12. for (int j = loc2; j < nums2.length; j++) {
  13. if (nums1[i] == nums2[j]) {
  14. ans = Math.max(ans, backTrace(i+1, j+1) + 1);
  15. break;
  16. }
  17. }
  18. }
  19. return ans;
  20. }
  21. }

时间复杂度爆炸,无法通过线上验证。

2)动态规划

  1. class Solution {
  2. public int maxUncrossedLines(int[] nums1, int[] nums2) {
  3. int[][] dp = new int[nums1.length + 1][nums2.length + 1];
  4. for (int i = 1; i < dp.length; i++) {
  5. for (int j = 1; j < dp[0].length; j++) {
  6. if (nums1[i-1] == nums2[j-1]) {
  7. dp[i][j] = dp[i-1][j-1] + 1;
  8. } else {
  9. dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
  10. }
  11. }
  12. }
  13. return dp[dp.length-1][dp[0].length-1];
  14. }
  15. }

nums1长度为m,nums2长度为n,时间复杂度为O(mn),空间复杂度为O(mn)。
进一步降低时间复杂度:

  1. class Solution {
  2. public int maxUncrossedLines(int[] nums1, int[] nums2) {
  3. int[] dp = new int[nums2.length + 1];
  4. for (int i = 0; i < nums1.length; i++) {
  5. int[] temp = new int[nums2.length + 1];
  6. for (int j = 1; j < dp.length; j++) {
  7. if (nums1[i] == nums2[j-1]) {
  8. temp[j] = dp[j-1] + 1;
  9. } else {
  10. temp[j] = Math.max(dp[j], temp[j-1]);
  11. }
  12. }
  13. dp = temp;
  14. }
  15. return dp[dp.length-1];
  16. }
  17. }

时间复杂度为O(mn),空间复杂度为O(n)。