【LetMeFly】1458.两个子序列的最大点积:动态规划
力扣题目链接:https://leetcode.cn/problems/max-dot-product-of-two-subsequences/
给你两个数组 nums1 和 nums2 。
请你返回 nums1 和 nums2 中两个长度相同的 非空 子序列的最大点积。
数组的非空子序列是通过删除原数组中某些元素(可能一个也不删除)后剩余数字组成的序列,但不能改变数字间相对顺序。比方说,[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 = [a1, a2,..., a*n*] 和 `b` = [b1, b2,..., b*n*] 的点积为:
这里的 Σ 指示总和符号。
解题方法:动态规划
令dp[i][j]表示nums1[0..i]与nums2[0..j]的子序列最大点积,那么则有状态转移方程:
cpp
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]
)
上述转移方程包含了所有 n u m s 1 [ i ] nums1[i] nums1[i]与 n u m s 2 [ j ] nums2[j] nums2[j]相乘和不相乘的情况。
- 时间复杂度 O ( l e n ( n u m s 1 ) × l e n ( n u m s 2 ) ) O(len(nums1)\times len(nums2)) O(len(nums1)×len(nums2))
- 空间复杂度 O ( l e n ( n u m s 1 ) × l e n ( n u m s 2 ) ) O(len(nums1)\times len(nums2)) O(len(nums1)×len(nums2))
当然,为了减少对 i − 1 i-1 i−1是否越界的判断,也可以给dp数组多开辟一行一列的空间,但注意这样的话多开辟那一行一列空间的初始值要小于等于 − 10 6 -10^6 −106(单个$nums1[i]\times nums2[j]最小值)。
AC代码
C++
cpp
/*
* @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
python
'''
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
java
/*
* @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
go
/*
* @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
rust
/*
* @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和我的个人博客,原创不易,转载经作者同意后请附上原文链接哦~
千篇源码题解已开源