目录
1. 问题目标的区别
(1)找到最长的等差数列
(2)统计等差数列的个数
2. 填表顺序的区别
(1)固定倒数第二个数(i)
(2)固定倒数第一个数(j)
3. 核心区别总结
4. 为什么选择不同的固定方式?
5. 总结
1. 问题目标的区别
(1)找到最长的等差数列
-
目标:找到数组中最长的等差数列的长度。
-
特点:需要关注的是等差数列的长度,而不是具体的个数。
-
动态规划状态定义:
dp[i][j]
表示以nums[i]
和nums[j]
结尾的等差数列的长度。 -
状态转移方程:
dp[i][j] = dp[k][i] + 1;
其中
k
是满足nums[k] = a
且k < i
的下标,a = 2 * nums[i] - nums[j]
。
(2)统计等差数列的个数
-
目标:统计数组中所有等差数列的个数。
-
特点:需要关注的是等差数列的数量,而不是长度。
-
动态规划状态定义:
dp[i][j]
表示以nums[i]
和nums[j]
结尾的等差数列的个数。 -
状态转移方程:
dp[i][j] += dp[k][i] + 1;
其中
k
是满足nums[k] = a
且k < i
的下标,a = 2 * nums[i] - nums[j]
。
2. 填表顺序的区别
(1)固定倒数第二个数(i
)
-
适用场景:找到最长的等差数列。
-
填表顺序:
-
外层循环固定
i
(倒数第二个数)。 -
内层循环枚举
j
(倒数第一个数)。
-
-
原因:
-
在计算
dp[i][j]
时,需要依赖dp[k][i]
,其中k
是i
的前一个位置。 -
固定
i
后,可以确保dp[k][i]
在计算dp[i][j]
时已经被计算。
-
-
示例代码:
for (int i = 1; i < n; i++) { // 固定倒数第二个数 for (int j = i + 1; j < n; j++) { // 枚举倒数第一个数 int a = 2 * nums[i] - nums[j]; // 计算前一个元素的值 if (hash.count(a)) { dp[i][j] = dp[hash[a]][i] + 1; // 更新 dp[i][j] } ret = max(ret, dp[i][j]); // 更新全局最大值 } }
(2)固定倒数第一个数(j
)
-
适用场景:统计等差数列的个数。
-
填表顺序:
-
外层循环固定
j
(倒数第一个数)。 -
内层循环枚举
i
(倒数第二个数)。
-
-
原因:
-
在计算
dp[i][j]
时,需要累加所有满足条件的dp[k][i]
,其中k
是i
的前一个位置。 -
固定
j
后,可以确保在计算dp[i][j]
时,所有可能的dp[k][i]
已经被计算。
-
-
示例代码:
for (int j = 2; j < n; j++) { // 固定倒数第一个数 for (int i = 1; i < j; i++) { // 枚举倒数第二个数 long long a = (long long)nums[i] * 2 - nums[j]; // 计算前一个元素的值 if (hash.count(a)) { for (auto k : hash[a]) { if (k < i) { dp[i][j] += dp[k][i] + 1; // 更新 dp[i][j] } } } sum += dp[i][j]; // 累加 dp[i][j] 到 sum } }
3. 核心区别总结
区别点 | 固定倒数第二个数(i ) | 固定倒数第一个数(j ) |
---|---|---|
适用场景 | 找到最长的等差数列 | 统计等差数列的个数 |
动态规划状态定义 | dp[i][j] 表示以 nums[i] 和 nums[j] 结尾的等差数列的长度 | dp[i][j] 表示以 nums[i] 和 nums[j] 结尾的等差数列的个数 |
状态转移方程 | dp[i][j] = dp[k][i] + 1 | dp[i][j] += dp[k][i] + 1 |
填表顺序 | 外层循环固定 i ,内层循环枚举 j | 外层循环固定 j ,内层循环枚举 i |
依赖关系 | 依赖 dp[k][i] ,其中 k 是 i 的前一个位置 | 依赖 dp[k][i] ,其中 k 是 i 的前一个位置 |
目标 | 找到最长的等差数列的长度 | 统计所有等差数列的个数 |
4. 为什么选择不同的固定方式?
-
固定倒数第二个数(
i
):-
适用于最长等差数列问题,因为需要确保在计算
dp[i][j]
时,dp[k][i]
已经被计算。 -
通过固定
i
,可以保证dp[k][i]
在计算dp[i][j]
时已经存在。
-
-
固定倒数第一个数(
j
):-
适用于统计等差数列个数问题,因为需要累加所有可能的
dp[k][i]
。 -
通过固定
j
,可以确保在计算dp[i][j]
时,所有可能的dp[k][i]
已经被计算。
-
5. 总结
-
固定倒数第二个数:适用于最长等差数列问题,填表顺序是从左到右、从下到上。
-
固定倒数第一个数:适用于统计等差数列个数问题,填表顺序是从左到右、从上到下。
两者的选择取决于问题的目标和状态转移方程的依赖关系。通过合理的固定方式,可以确保动态规划的正确性和高效性。