A sequence of numbers is called arithmetic if it consists of at least three elements and if the difference between any two consecutive elements is the same.

For example, these are arithmetic sequences:

1, 3, 5, 7, 9
7, 7, 7, 7
3, -1, -5, -9

The following sequence is not arithmetic.

1, 1, 2, 5, 7

A zero-indexed array A consisting of N numbers is given. A subsequence slice of that array is any sequence of integers (P0, P1, ..., Pk) such that 0 ≤ P0 < P1 < ... < Pk < N.

A subsequence slice (P0, P1, ..., Pk) of array A is called arithmetic if the sequence A[P0], A[P1], ..., A[Pk-1], A[Pk] is arithmetic. In particular, this means that k ≥ 2.

The function should return the number of arithmetic subsequence slices in the array A.

The input contains N integers. Every integer is in the range of -231 and 231-1 and 0 ≤ N ≤ 1000. The output is guaranteed to be less than 231-1.

Example:

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]

分析

又是一个光题目就得看半天的算法题,前面可以直接无视,直接看它给出的例子就知道这题到底要求什么了。看了下解答,方法是利用dp。

最少需要记住两个参数,序列的第一个或者最后一个元素,以及这个序列中的公共差。

f[i][d] denotes the number of arithmetic subsequences that ends with A[i] and its common difference is d.

下一步是寻找状态转移表达式已建立子问题之间的桥梁。试想如果我们现在想要把一个新元素A[i]插入到一个现有的arithmetic sequence中来形成一个新的arithmetic sequence,那么只有在A[i]和原来的sequence中最后一个元素的差等于其公共差的情况下才能形成新的arithmetic sequence。

这里比较难理解的便是 T(i, d) = summation of (1 + T(j, d)) as long as 0 <= j < i && d == A[i] - A[j].  这个式子,还是用个例子来说明比较好,如果当前的 j 是 3,公差是1的话 :

1,2,3,4

2,3,4

两个可能。3,4因为元素个数少于3个所以不构成arithmetic sequence,现在我们将A[i]=A[5]=5加入以构成新的arithmetic sequence,

1,2,3,4,5

2,3,4,5

3,4,5

多了一个,并不是完全等于之前的T(j, d)。

dp的特性,子问题之间有重复,和分治不同。

代码

public int numberOfArithmeticSlices(int[] A) {
int res = 0;
Map<Integer, Integer>[] map = new Map[A.length]; for (int i = 0; i < A.length; i++) {
map[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; 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;
}

map数组用来存储中间计算结果T(i, d),数组的index对应i,表示arithmetic sequence以A[i]结束;key是公共距离差d,value是arithmetic sequence的个数,也就是T(i, d)。也就说用了map数组一下子存储了三个基本信息,厉害了。

这题真的好难。

参考:https://leetcode.com/problems/arithmetic-slices-ii-subsequence/discuss/92822/Detailed-explanation-for-Java-O(n2)-solution

LeetCode446. Arithmetic Slices II - Subsequence的更多相关文章

  1. Arithmetic Slices II - Subsequence LT446

    446. Arithmetic Slices II - Subsequence Hard A sequence of numbers is called arithmetic if it consis ...

  2. [LeetCode] Arithmetic Slices II - Subsequence 算数切片之二 - 子序列

    A sequence of numbers is called arithmetic if it consists of at least three elements and if the diff ...

  3. LeetCode 446. Arithmetic Slices II - Subsequence

    原题链接在这里:https://leetcode.com/problems/arithmetic-slices-ii-subsequence/ 题目: A sequence of numbers is ...

  4. [Swift]LeetCode446. 等差数列划分 II - 子序列 | Arithmetic Slices II - Subsequence

    A sequence of numbers is called arithmetic if it consists of at least three elements and if the diff ...

  5. Leetcode: Arithmetic Slices II - Subsequence

    A sequence of numbers is called arithmetic if it consists of at least three elements and if the diff ...

  6. 446. Arithmetic Slices II - Subsequence

    A sequence of numbers is called arithmetic if it consists of at least three elements and if the diff ...

  7. 446 Arithmetic Slices II - Subsequence 算数切片之二 - 子序列

    详见:https://leetcode.com/problems/arithmetic-slices-ii-subsequence/description/ C++: class Solution { ...

  8. 第六周 Leetcode 446. Arithmetic Slices II - Subsequence (HARD)

    Leetcode443 题意:给一个长度1000内的整数数列,求有多少个等差的子数列. 如 [2,4,6,8,10]有7个等差子数列. 想了一个O(n^2logn)的DP算法 DP[i][j]为 对于 ...

  9. [LeetCode] Arithmetic Slices 算数切片

    A sequence of number is called arithmetic if it consists of at least three elements and if the diffe ...

随机推荐

  1. python之旅:网络基础之网络协议篇

    一.操作系统基础 操作系统:(Operating System,简称OS)是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才 ...

  2. linux Git版本控制学习与Git服务器搭建

    来源地址 要随时掌握工作区的状态,使用git status命令. 如果git status告诉你有文件被修改过,用git diff可以查看修改内容. 初始化一个Git仓库,使用git init命令. ...

  3. 转:iPhone上关于相机拍照的图片的imageOrientation的问题

    用相机拍摄出来的照片含有EXIF信息,UIImage的imageOrientation属性指的就是EXIF中的orientation信息.如果我们忽略orientation信息,而直接对照片进行像素处 ...

  4. fopen()、fwrite()、fread()函数使用说明与示例

    fopen()函数: 1.作用: 在C语言中fopen()函数用于打开指定路径的文件,获取指向该文件的指针. 2.函数原型: FILE * fopen(const char * path,const  ...

  5. jar包读取包内properties文件

    properties位于src目录下 project --src -----package -----test.properties Properties p = new Properties(); ...

  6. 2017 清北济南考前刷题Day 4 morning

    考场思路: 倒着算就是 可以对一个数-1 可以合并两个数 可以证明只有0和0才能执行合并操作 然后模拟 #include<cstdio> #include<iostream> ...

  7. 洛谷P1102 A-B数对

    洛谷P1102 A-B数对 https://www.luogu.org/problem/show?pid=1102 题目描述 出题是一件痛苦的事情! 题目看多了也有审美疲劳,于是我舍弃了大家所熟悉的A ...

  8. memcmp 和 memcpy使用

    #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> ...

  9. 【BZOJ】2655: calc 动态规划+拉格朗日插值

    [题意]一个序列$a_1,...,a_n$合法当且仅当它们都是[1,A]中的数字且互不相同,一个序列的价值定义为数字的乘积,求所有序列的价值和.n<=500,A<=10^9,n+1< ...

  10. SMTP——MIME

    MIME 基础知识 MIME 表示多用途 Internet 邮件扩允协议.MIME 扩允了基本的面向文本的 Internet 邮件系统,以便可以在消息中包含二进制附件. MIME 信息由正常的 Int ...