解题方法
本题我用两种方法尝试过:
- 暴力法(TLE超时了不推荐,O(n^3)的复杂度)
- 动态规划法
- 空间复杂度O(N^2)(申请了一个长度为为N的list对应每个数字;每个list元素装着一个O(N)的字典,用于存储以当前数字作为等差子序列结尾时,等差间隔key和这一等差间隔对应的序列长度value)
- 时间复杂度O(N^2) (第一层循环以每个数字i作为结尾,第二层循环遍历原序列的开始->第一层循环的i)
1、暴力法原理:
本质原理是:找出所有可能的等差序列,同时统计了它们的长度。如何找所有的序列?对于一个长度N的原序列(N > 2),以其中两个元素作为等差序列的开头,遍历其后的所有元素即可知道还有哪些等差的数值属于这个等差数列。使用一个dp[N][N]的矩阵便可以存储所有的可能序列的长度(还会有一半用不到,因为0<=i<j<N-1)。
- 第一步,从序列中选择两个元素(两个元素有前后相对的顺序)作为等差子序列的开头,这一步需要两层循环O(N^2)。
- 第二步,以之前的两个元素作为开头,遍历两个元素后面的元素,判断元素是否为以这两个元素作为开头的等差数O(N)
- 合起来O(N^3)
2、动态规划思路:
这道题使用动态规划的难点在于,它和我们通常看到的动态规划不太一样,拐了个弯
- 为什么可以用动态规划?
- 如图使用一个dp[N]的list作为备忘录,list中每个元素是一个字典(或者map)。
- 如上图所示,假设我们以子序列的角度来看问题:例如原始序列s=2 4 6 9 4,取出其中的s1=2 4,s2=2 4 6,s2比s1多了一个元素。在s1中我们可以计算等差值得到值为2的最长等差子序列长度为2(s1中的最长,现在有一点最优子结构的意思了吧!)。我们把这一长度记录在dp[1]的字典中(记为<差值:2, 长度:2>)——随后,当我们想求得s2中的最长子序列长度时,通过计算差值6-4=2,然后在dp[1]中查找差值为2的记录<2, 2>,通过对长度2+1,则可得到以6结尾的最长等差序列长度为3 ——得到键值对 <2, 3>(对于<4, 2>是同一步骤,代码中要实现)
- 所以转移方程为dp[ i ][ i和j的等差值 ] = dp[ j ][ i和j的等差值 ] + 1
- 依次对原序列中元素i使用动态规划的状态转移,就可以最终获得所有可能的最长序列长度
- 如果当前结尾 i 和它前面其他元素计算得到的等差值,不在其他元素对应的dp[ j ]字典中,怎么办?
- 此时则是说明只有它们两个可以组成等差序列,所以使dp[i][等差值] = 2更新状态即可
class