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

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

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

给你两个数组 nums1nums2

请你返回 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 = [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和我的个人博客,原创不易,转载经作者同意后请附上原文链接哦~

千篇源码题解已开源

相关推荐
好学且牛逼的马1 小时前
【Hot100|18-LeetCode 54. 螺旋矩阵】
算法·leetcode·矩阵
孞㐑¥1 小时前
算法—模拟
c++·经验分享·笔记·算法
2401_891450461 小时前
C++中的职责链模式实战
开发语言·c++·算法
m0_708830961 小时前
C++中的原型模式变体
开发语言·c++·算法
YuTaoShao1 小时前
【LeetCode 每日一题】3602. 十六进制和三十六进制转化——(解法二)手写进制转换
linux·python·leetcode
!停1 小时前
数据结构时间复杂度
c语言·开发语言·算法
AI科技星1 小时前
电磁光速几何耦合常数 Z‘ 的几何起源、第一性原理推导与多维度验证
人工智能·线性代数·算法·矩阵·数据挖掘
每天要多喝水1 小时前
贪心算法专题Day19
算法·贪心算法
Sarvartha1 小时前
图论基础与遍历算法(BFS+DFS)
算法·深度优先
努力学算法的蒟蒻1 小时前
day70(1.29)——leetcode面试经典150
算法·leetcode·面试