题目描述
思路
定义dp[i][j]
的含义是到nums1[i-1]
和nums2[j-1]
为止的子序列的最大点积。
则:其中dp[i][j]
的值 有5种选择,
- (1)只选择
nums1[i-1]
和nums2[j-1]
,即dp[i][j] = nums1[i-1]* nums2[j-1]
- (2)选择
nums1[i-1]
,不选择nums2[j-1]
,即dp[i][j] = dp[i][j-1]
- (3)不选择
nums1[i-1]
,选择nums2[j-1]
,即dp[i][j] = dp[i-1][j]
- (4)选择
nums1[i-1]
和nums2[j]
,同时选择前面的,即dp[i][j] = dp[i-1][j-1] + nums1[i-1]* nums2[j-1]
- (5)只选择
dp[i-1][j-1]
,即dp[i][j] = dp[i-1][j-1]
时间复杂度O(mn),空间复杂度O(mn)
但是对于第一行 和 第一列用 0
初始化的话,上述第 (1)
和 第 (5)
条是冗余的,证明如下:
-
如图所示,
dp[i-1][j-1]
,dp[i][j-1]
,dp[i-1][j]
都是有 红色星星状态转移过来的,而红色星星最终也都是中边界0
状态转移过来的。所以每个框框的值不可能为负数,而(1)
的状态转移式子是为了防止之前的数据为负数,故可以排除(1)
-
对于
(5)
式,上图中的dp[i-1][j-1]
一定小于等于dp[i][j-1]
和dp[i-1][j-1]
一定小于等于dp[i-1][j]
。因为dp[i-1][j-1]
是dp[i][j-1]
,dp[i-1][j]
状态转移过来的。 故排除(5)
。 -
代码如下
from typing import List
class Solution(object):
def maxDotProduct(self, A, B):
if all(a < 0 for a in A) and (b > 0 for b in B): return max(A) * min(B)
if all(a > 0 for a in A) and (b < 0 for b in B): return min(A) * max(B)
n,m = len(A), len(B)
dp = [[0] * (m + 1) for i in range(n + 1)]
for i in range(1, n+1):
for j in range(1, m+1):
dp[i][j] = max(dp[i-1][j], dp[i][j-1], dp[i-1][j-1] + A[i-1]*B[j-1])
for one in dp:
print(one)
return dp[n][m]