【Leetcode】1537. Get the Maximum Score

    科技2022-08-14  93

    题目地址:

    https://leetcode.com/problems/get-the-maximum-score/

    给定两个严格递增数组 A A A B B B,一条合法路径的定义为: 1、可以从 A [ 0 ] A[0] A[0]或者 B [ 0 ] B[0] B[0]开始向右走; 2、如果走到了某个数 A [ i ] = B [ j ] A[i]=B[j] A[i]=B[j],可以转到另一个数组继续向右走。 一条合法路径的得分定义为该路径的数字和。如果中途转到另一个数组了,交叉点的那个数只算一次。问最大分数是多少。答案返回的时候要模一下 1 0 9 + 7 10^9+7 109+7

    思路是动态规划。设 f [ i ] f[i] f[i]是以 A [ i ] A[i] A[i]为结尾的合法路径的最大得分(准确的说,是合法路径的到 A [ i ] A[i] A[i]为止的这一段的最大得分),设 g [ i ] g[i] g[i]是以 B [ i ] B[i] B[i]为结尾的合法路径的最大得分。那么,如果 A [ i ] A[i] A[i]不存在与 B B B中,那么 f [ i ] = f [ i − 1 ] + A [ i ] f[i]=f[i-1]+A[i] f[i]=f[i1]+A[i],同理如果 B [ i ] B[i] B[i]不存在于 A A A中,则 g [ i ] = g [ i − 1 ] + B [ i ] g[i]=g[i-1]+B[i] g[i]=g[i1]+B[i]。如果 A [ i ] = B [ j ] A[i]=B[j] A[i]=B[j],那么 f [ i ] = g [ j ] = max ⁡ { f [ i − 1 ] , g [ j − 1 ] } + A [ i ] f[i]=g[j]=\max\{f[i-1],g[j-1]\}+A[i] f[i]=g[j]=max{f[i1],g[j1]}+A[i]我们发现,为了得到 f [ i ] f[i] f[i],不仅 f [ 0 : i − 1 ] f[0:i-1] f[0:i1]要算出来,所有小于 A [ i ] A[i] A[i] B B B对应的下标的 g g g数组也都要算出来。由于数组是严格递增的,所以可以考虑用两个指针 i i i j j j,分别指向 A A A B B B,当 A [ i ] < B [ j ] A[i]<B[j] A[i]<B[j]的时候更新 f [ i ] f[i] f[i],当 A [ i ] > B [ j ] A[i]>B[j] A[i]>B[j]的时候更新 g [ j ] g[j] g[j],当 A [ i ] = B [ j ] A[i]=B[j] A[i]=B[j]的时候同时更新 f [ i ] f[i] f[i] g [ j ] g[j] g[j],这样就能达到效果。最后要返回的答案就是 max ⁡ { f [ l A − 1 ] , g [ l B − 1 ] } \max\{f[l_A-1],g[l_B-1]\} max{f[lA1],g[lB1]}。代码如下:

    public class Solution { public int maxSum(int[] nums1, int[] nums2) { int MOD = (int) (1e9 + 7); // 为了防止溢出,用long数组 long[] dp1 = new long[nums1.length], dp2 = new long[nums2.length]; int i = 0, j = 0; while (i < nums1.length && j < nums2.length) { if (nums1[i] < nums2[j]) { dp1[i] = ((i >= 1 ? dp1[i - 1] : 0) + nums1[i]); i++; } else if (nums1[i] > nums2[j]) { dp2[j] = ((j >= 1 ? dp2[j - 1] : 0) + nums2[j]); j++; } else { dp1[i] = dp2[j] = (Math.max(i >= 1 ? dp1[i - 1] : 0, j >= 1 ? dp2[j - 1] : 0) + nums1[i]); i++; j++; } } while (i < nums1.length) { dp1[i] = (i >= 1 ? dp1[i - 1] : 0) + nums1[i]; i++; } while (j < nums2.length) { dp2[j] = (j >= 1 ? dp2[j - 1] : 0) + nums2[j]; j++; } return (int) (Math.max(dp1[nums1.length - 1], dp2[nums2.length - 1]) % MOD); } }

    时空复杂度 O ( l A + l B ) O(l_A+l_B) O(lA+lB)

    考虑空间优化。我们可以只用两个变量做更新。代码如下:

    public class Solution { public int maxSum(int[] nums1, int[] nums2) { int MOD = (int) (1e9 + 7); long dp1 = 0, dp2 = 0; int i = 0, j = 0; while (i < nums1.length || j < nums2.length) { if (i < nums1.length && j < nums2.length) { if (nums1[i] < nums2[j]) { dp1 += nums1[i++]; } else if (nums1[i] > nums2[j]) { dp2 += nums2[j++]; } else { dp1 = dp2 = Math.max(dp1, dp2) + nums1[i]; i++; j++; } } else if (i < nums1.length) { dp1 += nums1[i++]; } else { dp2 += nums2[j++]; } } return (int) (Math.max(dp1, dp2) % MOD); } }

    时间复杂度不变,空间 O ( 1 ) O(1) O(1)

    Processed: 0.009, SQL: 8