413. 等差数列划分➕446. 等差数列划分 II - 子序列
413题目:
如果一个数列至少有三个元素,并且任意两个相邻元素之差相同,则称该数列为等差数列。
例如,以下数列为等差数列:
1, 3, 5, 7, 9
7, 7, 7, 7
3, -1, -5, -9
以下数列不是等差数列。
1, 1, 2, 5, 7
数组 A 包含 N 个数,且索引从0开始。数组 A 的一个子数组划分为数组 (P, Q),P 与 Q 是整数且满足 0<=P<Q<N 。
如果满足以下条件,则称子数组(P, Q)为等差数组:
元素 A[P], A[p + 1], ..., A[Q - 1], A[Q] 是等差的。并且 P + 1 < Q 。
函数要返回数组 A 中所有为等差数组的子数组个数。
示例:
A = [1, 2, 3, 4]
返回: 3, A 中有三个子等差数组: [1, 2, 3], [2, 3, 4] 以及自身 [1, 2, 3, 4]。
解答:
数学法:
找连续的等差数列i~j,如0~5,那么该区间能构成等差数列为(6-2)*(1+6-2)/2=10。即长度为3的:4个,长度4的:3个,长度5的:2个,长度6的:1个。
class Solution { public: int numberOfArithmeticSlices(vector<int>& A) { int n=A.size(); if(n<3){ return 0; } int res=0; vector<bool> flag(n,false); for(int i=2;i<n;++i){ if(A[i-1]-A[i-2]==A[i]-A[i-1]){ flag[i]=true; } } for(int i=2;i<n;){ if(flag[i]==false){ ++i; } int cnt=0; while(i<n and flag[i]){ ++i; ++cnt; } res+=(cnt+1)*cnt/2; } return res; } };
动态规划:
dp[i]=dp[i-1]+1 dp[i]表示以i结尾的等差数列数量,总结果为所有dp[i]之和。
class Solution { public: int numberOfArithmeticSlices(vector<int>& A) { int n=A.size(); vector<int> dp(n,0); int res=0; for(int i=2;i<n;++i){ if(A[i]-A[i-1]==A[i-1]-A[i-2]){ dp[i]=dp[i-1]+1; } res+=dp[i]; } return res; } };
446题目:
如果一个数列至少有三个元素,并且任意两个相邻元素之差相同,则称该数列为等差数列。
例如,以下数列为等差数列:
1, 3, 5, 7, 9
7, 7, 7, 7
3, -1, -5, -9
以下数列不是等差数列。
1, 1, 2, 5, 7
数组 A 包含 N 个数,且索引从 0 开始。该数组子序列将划分为整数序列 (P0, P1, ..., Pk),P 与 Q 是整数且满足 0 ≤ P0 < P1 < ... < Pk < N。
如果序列 A[P0],A[P1],...,A[Pk-1],A[Pk] 是等差的,那么数组 A 的子序列 (P0,P1,…,PK) 称为等差序列。值得注意的是,这意味着 k ≥ 2。
函数要返回数组 A 中所有等差子序列的个数。
输入包含 N 个整数。每个整数都在 -231 和 231-1 之间,另外 0 ≤ N ≤ 1000。保证输出小于 231-1。
示例:
输入:[2, 4, 6, 8, 10]
输出:7
解释:
所有的等差子序列为:
[2,4,6]
[4,6,8]
[6,8,10]
[2,4,6,8]
[4,6,8,10]
[2,4,6,8,10]
[2,6,10]
解答:
还是和上一题差不多的方法,但由于这题等差数列可以不相邻,比如1,2,3,5,6,7。可以选择1,3,5这样的子序列作为等差数列。那么考虑对于以i结尾的等差数列来说,对于k(0<k<i),若以k结尾的等差数列存在,且数量为X。则以i结尾的等差数列数量可以直接加X+1。但问题是以k结尾的等差数列可能有多种公差,每个公差有各自的数量。所以DP不仅要保存数量,还要保存公差。
那么我们使用一个vector< map <int ,int > >来作为dp数组。
含义:dp[i]是一个map,dp[i][j]表示以索引i结尾的、公差为j的等差数列有几个。
另外这题要用long,不然有的用例过不去。
class Solution { public: int numberOfArithmeticSlices(vector<int>& A) { int n=A.size(); if(n<3){return 0;} unordered_map<long,unordered_set<int> >mp;//mp[i]:stores all j which suits: A[j]==i for(int i=0;i<n;++i){ mp[long(A[i])].insert(i); } int res=0; vector<unordered_map<long,long> >dp(n);//dp[i] is a map,dp[i][j]:i结尾、公差j的等差数列有几个 for(int i=0;i<n-2;++i){ for(int j=i+1;j<n-1;++j){ long val=long(A[j])*2-long(A[i]); if(mp.count(val)){ for(int k:mp[val]){ if(k>j){ dp[k][val-A[j]]+=1; // cout<<A[i]<<A[j]<<A[k]<<" "<<val<<endl; } } } } } long dif; for(int i=2;i<n;++i){ for(int j=i-1;j>=2;--j){ dif=long(A[i])-long(A[j]);//公差 if(dp[j].count(dif)){ dp[i][dif]+=dp[j][dif]; } } } for(int i=2;i<n;++i){ for(auto& pair:dp[i]){ res+=pair.second; } } return res; } };