leetcode算法题--等差数列划分

原题链接:https://leetcode-cn.com/problems/arithmetic-slices/

采用动态规划

dp[i][j]表示从i到j的子数组是否为等差数组

转移方程:

 dp[i][i+len]=dp[i][i+len-1]&&A[j]-A[j-1]==A[j-1]-A[j-2];

len从3开始增加,判断每个长度的子数组是否为等差数组,并且依赖前面的状态,比如len=4的数组[i,i+3]依赖len=3的[i,i+2],并判断A[i+3]是否与前面构成等差。

 inline bool func(vector<int> &A,int j){
     return A[j]-A[j-1]==A[j-1]-A[j-2];
 }
 int numberOfArithmeticSlices(vector<int>& A) {
     int size=A.size();
     vector<vector<int>> dp(size,vector<int>(size,0));
     int count=0;
     for(int i=0,j=i+2;i<size-2;i++,j++){
         dp[i][j]=func(A,j)?1:0;
         count+=dp[i][j];
     }
     for(int len=3;len<size;len++){
         for(int i=0,j=i+len;i<size-len;i++,j++){
                 dp[i][j]=dp[i][j-1]&&func(A,j)?1:0;
                 count+=dp[i][j];
         }
     }
     return count;
 }

不过看了题解之后,发现这个动态规划是可以优化的,就是其实可以省略len依次递增,然后再判断。因为想象这样一个场景,[0,2]这个数组是等差的,计数为1,然后[1,3]这个数组也是等差的话,计数直接为2,因为这种情况下默认[0,3]也是等差的了,最后把所有计数加起来即可!

    inline bool func(vector<int> &A,int j){
        return A[j]-A[j-1]==A[j-1]-A[j-2];
    }
    int numberOfArithmeticSlices(vector<int>& A) {
        int size=A.size();
        if(size<3) return 0;
        vector<int> dp(size,0);
        int count=0;
        for(int i=0,j=i+2;i<size-2;i++,j++){
            if(func(A,j))
                dp[j]=dp[j-1]+1;
            count+=dp[j];
        }
        return count;
    }

并且还能不用dp数组,因为每次循环只和dp,dp[j-1]有关

    inline bool func(vector<int> &A,int j){
        return A[j]-A[j-1]==A[j-1]-A[j-2];
    }
    int numberOfArithmeticSlices(vector<int>& A) {
        int size=A.size();
        if(size<3) return 0;
        int dp=0;
        int count=0;
        for(int i=0,j=i+2;i<size-2;i++,j++){
            if(func(A,j))
                dp=dp+1;
            else
                dp=0;
            count+=dp;
        }
        return count;
    }

你可能感兴趣的:(算法)