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

千篇源码题解已开源

相关推荐
求梦82016 小时前
【力扣hot100题】合并区间(9)
算法·leetcode·职场和发展
汽车仪器仪表相关领域16 小时前
工况模拟精准检测,合规减排赋能行业 ——NHASM-1 型稳态工况法汽车排气检测系统项目实战经验分享
数据库·算法·单元测试·汽车·压力测试·可用性测试
chilavert31816 小时前
技术演进中的开发沉思-299 计算机原理:数据结构
算法·计算机原理
C+-C资深大佬16 小时前
C++逻辑运算
开发语言·c++·算法
天天进步201516 小时前
KrillinAI 源码级深度拆解二:时间轴的艺术:深入 KrillinAI 的字幕对齐与音频切分算法
算法·音视频
爱编程的小吴16 小时前
【力扣练习题】121. 买卖股票的最佳时机
算法·leetcode·职场和发展
生信大杂烩16 小时前
空间转录组分析新工具 | MEcell:自适应微环境感知建模,精准解析细胞身份!
算法·数据分析
kaikaile199516 小时前
计算向量x的功率谱密度
算法
ADI_OP17 小时前
ADAU1452的开发教程3:常规音频算法的开发(1)
算法·音视频·adi dsp中文资料·adi dsp开发教程