DP+MAP 解题 Longest Arithmetic Subsequence

46 阅读2分钟

给定一个整数数组,返回其中最长的等差子序列的长度。子序列是原数组中任意几个元素按原顺序组成的新序列,不要求连续。

Example 1:

Input: nums = [3,6,9,12]
Output: 4
Explanation: The whole array is an arithmetic sequence with steps of length = 3.

🔍 解题思路:

动态规划 的思想解决这个问题,核心是维护以每个元素结尾的、不同差值的最长等差序列长度。

🔑 关键点:

  • 用一个数组 dp[i] 表示以 array[i] 结尾的所有差值对应的最长等差序列。

  • dp[i] 是一个 Map<Integer, Integer>,键是差值 diff,值是以这个差值结尾的最长子序列长度。

  • 对于每个元素 array[i],往前找所有 j<i 的元素,计算差值 diff = array[i] - array[j]

    • 如果 dp[j] 中没有这个差值,说明当前是新开始的长度为 2 的序列。
    • 否则,就可以接在 dp[j].get(diff) 的基础上,长度 +1。

📌 代码解释

public class LongestArithSequenceLength {

public int longestArithSequenceLength(int[] array) {
    if (array == null || array.length < 2) return 0;

    int globalMax = 0;
    Map<Integer, Integer>[] dp = new Map[array.length];

    for (int i = 0; i < array.length; i++) {
        dp[i] = new HashMap<>();
        for (int j = 0; j < i; j++) {
            int diff = array[i] - array[j];
            // 如果之前没有这种差值的序列,从2开始
            int len = dp[j].getOrDefault(diff, 1) + 1;
            dp[i].put(diff, len);
            globalMax = Math.max(globalMax, len);
        }
    }
    return globalMax;
}

}

⏱️ 时间复杂度:

  • 外层两层循环:O(n^2)
  • 内部的 HashMap 操作是 O(1) 平均时间
    ✅ 所以总时间复杂度是:O(n²)

🧠 总结:

这道题考察的是动态规划中对状态定义和存储结构的掌握:

  • 如何定义状态 dp[i]
  • 如何表示差值 diff
  • 如何记录历史并延长已有序列

它是典型的“状态依赖之前所有结果”类型问题,非常适合巩固对动态规划的理解。