21-8-11 等差数列划分 II - 子序列

446. 等差数列划分 II - 子序列 难度[困难]


给你一个整数数组 nums ,返回 nums 中所有 等差子序列 的数目。

如果一个序列中 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该序列为等差序列。

  • 例如,[1, 3, 5, 7, 9]、[7, 7, 7, 7] 和 [3, -1, -5, -9] 都是等差序列。
  • 再例如,[1, 1, 2, 5, 7] 不是等差序列。

数组中的子序列是从数组中删除一些元素(也可能不删除)得到的一个序列。

  • 例如,[2,5,10] 是 [1,2,1,2,4,1,5,10] 的一个子序列。

题目数据保证答案是一个 32-bit 整数。

示例 1:

输入:nums = [2,4,6,8,10]
输出:7
解释:所有的等差子序列为:
[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]

示例 2:

输入:nums = [7,7,7,7,7]
输出:16
解释:数组中的任意子序列都是等差子序列。

提示:

  • 1  <= nums.length <= 1000
  • -2^31 <= nums[i] <= 2^31 - 1

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/arithmetic-slices-ii-subsequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


解法一:DP

class Solution {
    public int numberOfArithmeticSlices(int[] nums) {
        int n = nums.length;
        // Map   Long等差值 d ,Integer cnt 等差值为d的数量
        List<Map<Long,Integer>> f = new ArrayList<>();
        for(int i=0 ; i<n ; i++){
            Map<Long,Integer> cur = new HashMap<>();
            for(int j=0 ; j<i ; j++){
                Long d = nums[i]*1L - nums[j];
                //获取以 j 结尾的弱等差数列集合
                Map<Long,Integer> pre = f.get(j);
                //累加前缀
                int cnt = cur.getOrDefault(d,0);
                cnt += pre.getOrDefault(d,0);
                //本次添加
                cnt ++;
                cur.put(d,cnt);
            }
            f.add(cur);
        }
        //求出所有等差数列的数量
        int ans = 0;
        for(int i=0 ; i<n ; i++){
            Map<Long,Integer> cur = f.get(i);
            for(Long key : cur.keySet()) ans += cur.get(key);
        }
        //求出长度为 2 的数列数量
        // 长度为 n 的数组的所有数对,其实就是求 首项为 0,末项为 n - 1,
        // 公差为 1,长度为 n 的等差数列之和,直接使用「等差数列求和」公式求解即可
        int a1 =0, an = n-1;
        int cnt = (a1+an)*n/2;

        return ans-cnt;
    }
}

参考


此文章创于本人学习时的记录,如有错误或更优解还请指出

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