413. Arithmetic Slices

一、题目简述

一个序列被称为是算术的,如果它至少包含三个元素,并且序列中任意两个相邻元素之差相同。
例如,以下序列是算术的:

1, 3, 5, 7, 9
7, 7, 7, 7
3, -1, -5, -9

以下序列不是算术的:

1, 1, 2, 5, 7

一个下标从零开始的数组A包含N个元素。使用整数对(P,Q), 0P<Q<N ,来表示数组的一个片段。

数组的一个片段(P,Q)是算术的,如果满足:A[P],A[P+1],…,A[Q-1],A[Q]是算术的,并且P+1 < <script type="math/tex" id="MathJax-Element-227"><</script>Q。

函数返回数组A中算术片段的个数。
例如:
A = [1, 2, 3, 4]
返回: 3,该数组含有的算术序列如下:[1, 2, 3], [2, 3, 4] 和 [1, 2, 3, 4]。

函数原型:
int numberOfArithmeticSlices(vector<int>& A)

二、编程思路

该题可以使用动态规划思路进行求解,提供两种解题思路,第一种思路的时间复杂度为 O(N2) ,第二种思路的时间复杂度为 O(N)

2.1 简单思路

状态定义:令dp[i][j]表示数组A的A(i,j)片段是否为算术序列。
状态转移方程:

  • 若i=j-2,则dp[i][j]=(2*A[i+1]==A[i]+A[j]);
  • 若i < <script type="math/tex" id="MathJax-Element-246"><</script>j-2,则dp[i][j]=dp[i][j-1]&&(2*A[j-1]==A[j]+A[j-2]);该状态转移方程较为容易理解,表示如果片段A(i,j-1)为算术序列,并且新加入的元素A[j]能与之前序列构成算术序列,则片段A(i,j)为算术的。之后统计A所有片段中算术片段的个数即可。
2.2 升级思路

由以上分析可以看出,2.1中的思路其实枚举了A的所有片段,之后判断其是否为算术片段。并且在递推式dp[i][j]=dp[i][j-1]&&(2*A[j-1]==A[j]+A[j-2]);中并未用到i的信息,因此可以考虑将问题简化为 O(N) 的复杂度。

  • 状态定义:令dp[i]表示以i结尾的最长算术片段的长度。并且初始值均为2。
  • 状态转移方程:若2 A[i-1]==A[i]+A[i-2],则dp[i]=dp[i-1]+(2A[i-1]==A[i]+A[i-2]);否则,dp[i]=2;
  • 对于一个长度为len (len>2) 的算术片段,其包含的子算术片段的个数为: (len1)(len2)2
  • 据此,避免重复情况,如,序列A={1, 2 ,3 ,4},其dp={2, 2, 3, 4},只应计算dp[3]=4的子片段数量。求出A中算术子片段的个数即可。

三、程序设计

3.1 简单思路
class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& A) {
        int size=A.size();
        if(size<3) return 0;
        vector<vector<bool> >dp(size,vector<bool>(size,false));
        int sum=0;
        for(int i=0;i<size;i++){
            for(int j=i+2;j<size;j++){
                if(j==i+2) dp[i][j]=(2*A[i+1]==A[i]+A[j]);
                else{
                    dp[i][j]=dp[i][j-1]&&(2*A[j-1]==A[j]+A[j-2]);
                }
                if(dp[i][j]) sum++;
            }
        }
        return sum;
    }
};
3.2 升级思路
class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& A) {
        int size=A.size();
        if(size<3) return 0;
        int start=0,sum=0;
        for(int i=2;i<size;i++){
            int len=i-start+1;
            if(2*A[i-1]==A[i-2]+A[i]){
                if(i==size-1 && len>2){
                    sum+=(len-1)*(len-2)/2;
                }
            }else{
                len--;
                if(len>2) sum+=(len-1)*(len-2)/2;
                start=i-1;
            }
        }
        return sum;
    }
};

四、参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值