1. 题目解析与核心概念
今天我们来拆解力扣第1458题——"两个子序列的最大点积"。这是一道典型的动态规划问题,考察我们对子序列和点积概念的理解,以及如何将问题分解为可递归解决的子问题。
首先明确几个关键概念:
-
子序列:通过删除原数组中某些元素(可能一个也不删除)后剩余数字组成的序列,但不能改变数字间相对顺序。例如:
- [2,3,5] 是 [1,2,3,4,5] 的子序列
- [1,5,3] 不是 [1,2,3,4,5] 的子序列(顺序改变了)
-
点积:对于两个长度相同的序列a和b,它们的点积是对应位置元素相乘后的总和。数学表达式为:
code复制a·b = Σ(a_i * b_i) for i from 1 to n
题目要求我们找到nums1和nums2中两个长度相同的非空子序列,使它们的点积最大。注意几个关键约束:
- 子序列必须非空
- 两个子序列长度必须相同
- 可以全选原数组(即子序列等于原数组本身)
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动态规划解题思路
2.1 问题分析与状态定义
这道题属于典型的二维动态规划问题。我们需要考虑两个数组的各种组合情况,因此状态定义需要包含两个维度:
设 dp[i][j] 表示:
- nums1前i个元素(即nums1[0..i-1])
- nums2前j个元素(即nums2[0..j-1])
能构成的最大点积。
为什么这样定义?因为我们需要考虑两个数组的各种前缀组合,逐步构建最终解。
2.2 状态转移方程
对于每个位置(i,j),我们有几种选择:
-
只选择当前两个元素:即子序列只包含nums1[i-1]和nums2[j-1]
- 点积就是nums1[i-1] * nums2[j-1]
-
不选nums1当前元素:继承dp[i-1][j]的结果
- 相当于nums1的子序列不包含nums1[i-1]
-
不选nums2当前元素:继承dp[i][j-1]的结果
- 相当于nums2的子序列不包含nums2[j-1]
-
同时选择当前两个元素,并加上前面的最优解:
- dp[i-1][j-1] + nums1[i-1]*nums2[j-1]
- 这相当于在前面的最优子序列基础上追加当前两个元素
因此,状态转移方程为:
java复制dp[i][j] = max(
nums1[i-1] * nums2[j-1], // 只选当前两个
dp[i-1][j], // 不选nums1当前
dp[i][j-1], // 不选nums2当前
dp[i-1][j-1] + nums1[i-1
