Leetcode 446

给了一个数组,求等差数列有多少个,要求等差数列的长度至少为3. 比如:

Input: [2, 4, 6, 8, 10]

Output: 7

Explanation:
All arithmetic subsequence slices are:
[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]

数组长度N <= 1000, 数组元素的值在int范围内

这个题目显然是个dp题目,如何定义状态呢?

我们定义dp[i][diff]  表示为以nums[i]结尾的,公差为diff的等差数列的长度的个数. 这里的等差数列的长度至少为2

 

因此我们有如下转移方程:

dp[i][diff] = dp[j][diff] + 1, 其中j < i

什么意思呢?

以nums[i]结尾的公差为diff的等差数列 (长度>=2),可以由两种方式得到

    1: 直接和num[j]组合为 (nums[j], nums[i]),这样组成的长度为2

    2:以nums[j]结尾的公差为d的等差数列,也就是dp[j][diff],后面跟上nums[i]得到,这样组成的长度 >=3.

由以上分析,可以在得到dp[i][diff]的同时,可以把第二种情况累加到答案中去

于是我写出了这样的代码:

    public int numberOfArithmeticSlices(int[] A) {
        int len = A.length;

        int[][] dp = new int[len][1000010];
        //dp[i][d] 以 num[i]结尾的差为d等差数列的个数,这个等差数列长度至少为2
        int res = 0;

        for (int i = 0; i < len; i++) {
            for (int j = 0; j < i; j++) {
                //求出公差
                int diff = A[i] - A[j];

                //以nums[i]结尾的公差为diff的长度为>=2的等差数列可以由两种方式得来

                //1: (nums[j], nums[i])可以构成一个公差为diff的长度为2的等差数列
                //2:  dp[j][diff]表示以nums[j]公差为diff的长度为2的等差数列,我们在其后面加上一个nums[i],便可以构成长度>=3的等差数列
                //    我们可以把这部分累加到最终的答案里,因为题目要求等差数列的长度至少为3
                dp[i][diff] += 1;
                dp[i][diff] += dp[j][diff];

                res += dp[j][diff];
            }
        }
        return res;
    }

 

 

提交上去,显然过不了 如下的数据

0,2000000000,-294967296

因为数据是在int范围内的,因此第二维的diff空间肯定是存不下的,怎么办呢?使用一个map就可以解决这个问题了

    public int numberOfArithmeticSlices(int[] A) {
        int len = A.length;

        Map<Long, Integer>[] dp = new Map[len];
        //dp[i].get(d) 以 num[i]结尾的差为d等差数列的个数,这个等差数列长度至少为2
        int res = 0;

        for (int i = 0; i < len; i++) {
            dp[i] = new HashMap<>(i);
            for (int j = 0; j < i; j++) {
                //求出公差
                long diff = (long)A[i] - A[j];
                if (diff <= Integer.MIN_VALUE || diff >= Integer.MAX_VALUE) continue;
                //以nums[i]结尾的公差为diff的长度为>=2的等差数列可以由两种方式得来

                //1: (nums[j], nums[i])可以构成一个公差为diff的长度为2的等差数列
                //2:  dp[j].get(diff) 表示以nums[j]公差为diff的长度为2的等差数列,我们在其后面加上一个nums[i],便可以构成长度>=3的等差数列
                //    我们可以把这部分累加到最终的答案里,因为题目要求等差数列的长度至少为3
                int v = dp[i].getOrDefault(diff, 0);
                int add = dp[j].getOrDefault(diff, 0);
                v += add + 1;
                res += add;
                dp[i].put(diff, v);
            }
        }
        return res;
    }

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值