1458.两个子序列的最大点积:动态规划

【LetMeFly】1458.两个子序列的最大点积:动态规划

力扣题目链接:https://leetcode.cn/problems/max-dot-product-of-two-subsequences/

给你两个数组 nums1 和 nums2 。

请你返回 nums1nums2 中两个长度相同的 非空 子序列的最大点积。

数组的非空子序列是通过删除原数组中某些元素(可能一个也不删除)后剩余数字组成的序列,但不能改变数字间相对顺序。比方说,[2,3,5] 是 [1,2,3,4,5] 的一个子序列而 [1,5,3] 不是。

 

示例 1:

输入:nums1 = [2,1,-2,5], nums2 = [3,0,-6]
输出:18
解释:从 nums1 中得到子序列 [2,-2] ,从 nums2 中得到子序列 [3,-6] 。
它们的点积为 (2*3 + (-2)*(-6)) = 18 。

示例 2:

输入:nums1 = [3,-2], nums2 = [2,-6,7]
输出:21
解释:从 nums1 中得到子序列 [3] ,从 nums2 中得到子序列 [7] 。
它们的点积为 (3*7) = 21 。

示例 3:

输入:nums1 = [-1,-1], nums2 = [1,1]
输出:-1
解释:从 nums1 中得到子序列 [-1] ,从 nums2 中得到子序列 [1] 。
它们的点积为 -1 。

 

提示:

  • 1 <= nums1.length, nums2.length <= 500
  • -1000 <= nums1[i], nums2[i] <= 100

 

点积:

定义 a = [a1a2,…, an] b = [b1b2,…, bn] 的点积为:

\mathbf{a}\cdot \mathbf{b} = \sum_{i=1}^n a_ib_i = a_1b_1 + a_2b_2 + \cdots + a_nb_n 

这里的 Σ 指示总和符号。

解题方法:动态规划

dp[i][j]表示nums1[0..i]nums2[0..j]的子序列最大点积,那么则有状态转移方程:

1
2
3
4
5
6
dp[i][j] = max(
nums1[i] * nums1[j], // 不要前面的,从nums1[i]和nums2[j]开始
dp[i-1][j], // nums1[0..i-1]与nums2[0..j]的子序列最大点积
dp[i][j-1], // nums1[0..i]与nums2[0..j-1]的子序列最大点积
dp[i-1][j-1] + nums1[i]*nums1[j] // 前面的最大点积,加上nums1[i]*nums1[j]
)

上述转移方程包含了所有$nums1[i]$与$nums2[j]$相乘和不相乘的情况。

  • 时间复杂度$O(len(nums1)\times len(nums2))$
  • 空间复杂度$O(len(nums1)\times len(nums2))$

当然,为了减少对$i-1$是否越界的判断,也可以给dp数组多开辟一行一列的空间,但注意这样的话多开辟那一行一列空间的初始值要小于等于$-10^6$(单个$nums1[i]\times nums2[j]最小值)。

AC代码

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
* @LastEditTime: 2026-01-08 09:23:30
*/
class Solution {
public:
int maxDotProduct(vector<int>& nums1, vector<int>& nums2) {
int n = nums1.size(), m = nums2.size();
vector<vector<int>> dp(n, vector<int>(m));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
dp[i][j] = nums1[i] * nums2[j];
if (i) {
dp[i][j] = max(dp[i][j], dp[i - 1][j]);
}
if (j) {
dp[i][j] = max(dp[i][j], dp[i][j - 1]);
}
if (i && j) {
dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + nums1[i] * nums2[j]);
}
}
}
return dp[n - 1][m - 1];
}
};

Python

1
2
3
4
5
6
7
8
9
10
11
12
'''
LastEditTime: 2026-01-08 09:29:41
'''
from typing import List

class Solution:
def maxDotProduct(self, nums1: List[int], nums2: List[int]) -> int:
dp = [[-1000000000] * (len(nums2) + 1) for _ in range(len(nums1) + 1)]
for i, x in enumerate(nums1, 1):
for j, y in enumerate(nums2, 1):
dp[i][j] = max(x * y, dp[i-1][j], dp[i][j-1], dp[i-1][j-1] + x * y)
return dp[-1][-1]

Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
* @LastEditTime: 2026-01-08 09:45:31
*/
import java.util.Arrays;

class Solution {
public int maxDotProduct(int[] nums1, int[] nums2) {
int n = nums1.length, m = nums2.length;
int[][] dp = new int[n+1][m+1];
for (int i = 0; i <= n; i++) {
Arrays.fill(dp[i], -1000000);
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
dp[i][j] = Math.max(nums1[i-1] * nums2[j-1], Math.max(dp[i-1][j], Math.max(dp[i][j - 1], dp[i-1][j-1] + nums1[i-1] * nums2[j-1])));
}
}
return dp[n][m];
}
}

Go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
* @LastEditTime: 2026-01-08 09:36:59
*/
package main

func max1458_2(a, b int) int {
if a > b {
return a
}
return b
}

func max1458(a, b, c, d int) int {
return max1458_2(a, max1458_2(b, max1458_2(c, d)))
}

func maxDotProduct(nums1 []int, nums2 []int) int {
n, m := len(nums1), len(nums2)
dp := make([][]int, n + 1)
for i := range dp {
dp[i] = make([]int, m + 1)
for j := range dp[i] {
dp[i][j] = -1000000;
}
}

for i, x := range nums1 {
for j, y := range nums2 {
dp[i+1][j+1] = max1458(x*y, dp[i][j+1], dp[i+1][j], dp[i][j] + x*y)
}
}
return dp[n][m] // 不是dp[n-1][m-1]
}

Rust

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
* @LastEditTime: 2026-01-08 09:51:58
*/
impl Solution {
pub fn max_dot_product(nums1: Vec<i32>, nums2: Vec<i32>) -> i32 {
let n: usize = nums1.len();
let m: usize = nums2.len();
let mut dp: Vec<Vec<i32>> = vec![vec![-1000000; m+1]; n+1];
for i in 1..=n {
for j in 1..=m {
dp[i][j] = dp[i-1][j].max(dp[i][j-1].max((nums1[i-1] * nums2[j-1]).max(dp[i-1][j-1] + nums1[i-1] * nums2[j-1])));
}
}
dp[n][m]
}
}

同步发文于CSDN和我的个人博客,原创不易,转载经作者同意后请附上原文链接哦~

千篇源码题解已开源


1458.两个子序列的最大点积:动态规划
https://blog.letmefly.xyz/2026/01/08/LeetCode 1458.两个子序列的最大点积/
作者
发布于
2026年1月8日
许可协议