446. Arithmetic Slices II - Subsequence

446是413. Arithmetic Slices问题同思路的DP多维扩展版。

代码与说明

先给出413代码:

public int numberOfArithmeticSlices(int[] A) {
        int res=0;
        int dp=0;
        if(A.length<3)return res;
        int diff=A[1]-A[0]; // 默认搜索时动态地维护一个差值,不满足该差值时重启计算
        for(int i=2;i<A.length;i++){
            if(A[i]-A[i-1]==diff){
                dp=dp+1; //差值得到满足,数列持续扩充 
            }else{
                diff=A[i]-A[i-1]; //跳出当前差值数列
                dp=0;
            }
            res+=dp;
        }
        return res;
    }

dp代表的是在当前位置新增的等差数列个数;
当前满足条件A[i]-A[i-1]==diff时,代表可以在当前维护的等差数列后添加元素A[i],规则如下:

数组总长度\等差数列长度345
3100
4210
5321

dp[i]=dp[i-1]+1,亦即dp=dp+1
由于是将A[i]-A[i-1]A[i-1]-A[i-2]做比较,永远满足数列长度>=3,dp更新后即能累加到res上。
该问题只考虑了到达某一位置时有唯一的diff,而446题需要到达某一位置i后,考虑0<=j<i上,所有可能的diff

446参考高赞代码

public int numberOfArithmeticSlices(int[] A) {
        Map<Integer,Integer>[]map=new Map[A.length];
        int res=0;
        for(int i=0;i<A.length;i++){
            map[i]=new HashMap<>();
            for(int j=0;j<i;j++){
                long diff=(long)A[i]-A[j];
                if(diff>=Integer.MAX_VALUE||diff<=Integer.MIN_VALUE){
                    continue;
                }
                int d=(int)diff;
                int c1=map[i].getOrDefault(d,0);
                int c2=map[j].getOrDefault(d,0);
                res+=c2;
                map[i].put(d,c1+c2+1);
            }
        }
        return res;
    }

算法理解

(代码由后往前解释更容易)

到达位置i后,向前找到位置j,此时有想要寻找的等差数列差值diff=A[i]-A[j]

map[i].put(d,c1+c2+1)更新的是:由位置i作为数列末尾元素确定的差值为diff的等差数列,将来再遇到一个能被扩充到末尾的元素时,最终结果会增加的数列个数(预测值);由两部分组成:之前已预测的c1和本次新预测的c2+1;将会作为c1c2在以后参与计算。

int c2=map[j].getOrDefault(d,0)得到的是j位置上预测的如果A[i]可以扩充等差数列,则最终结果会增加的数列个数(道理同上表解释dp=dp+1);c2=0代表A[i]A[j]形成了新的长度为2的预备等差数列,下一次再遇到可扩充元素,等效为在总结果上+1;c2!=0代表A[i]可以扩充到由位置j作为数列末尾元素确定的差值为diff的等差数列,且造成总结果res+=c2

int c1=map[i].getOrDefault(d,0)得到的是该i之前由其他j确定的预测值,在本次j循环找新的预测值后,需要将其累加上去。
例如[2,2,4,6]i=2c1=map[2].get(2)先在j=0时等于0,接着在j=1时等于1,更新位置i=2的预测值时,以元素4为结尾,diff=2的预备等差数列有两个。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值