413. Arithmetic Slices

来源:互联网 发布:在贵州吃腊肉 知乎 编辑:程序博客网 时间:2024/06/05 08:20

一、题目简述

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

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<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<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。
  • 状态转移方程:若2A[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
原创粉丝点击