[Leetcode] 446. Arithmetic Slices II - Subsequence 解题报告
2017-11-10 16:04
435 查看
题目:
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:
The following sequence is not arithmetic.
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.
思路:
1、回溯法:我开始自然而然地想到了回溯法,也就是每个元素我们试着将它加入等差数列中,看看是否符合要求,然后再将它取出来。最终统计出符合条件的等差数列的个数。然而却无法通过大数据测试,因为对于[1,1,1,1,1,1,1,1,1,1,1,1]这样的测试用例,回溯法会涉及到大量的重复计算。
2、动态规划:定义dp[index][diff]表示以A[index]结尾,等差值为diff的序列的个数,那么状态转移方程为dp[index][diff] = sum(dp[i][diff] + 1),其中0 <= i <= index - 1。注意sum内部+1是由于包含了A[index]本身。在实现中,由于以A[index]结尾的序列的diff个数可能是稀疏的, 所以我们采用vector<unordered_map<int,int>> 这种数据结构来表示dp。这种算法的时间复杂度是O(n^2),可以顺利通过大数据测试。
代码:
1、回溯法:
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& A) {
vector<int> line;
int count = 0;
DFS(A, 0, line, count);
return count;
}
private:
void DFS(vector<int> &A, int index, vector<int> &line, int &count) {
if (index == A.size()) {
if (line.size() >= 3) {
++count;
}
return;
}
// include A[index]
if (line.size() < 2) {
// include A[index]
line.push_back(A[index]);
DFS(A, index + 1, line, count);
line.pop_back();
}
else { // line.size() >= 2
// A[index] can be included
int size = line.size();
long long diff1 = static_cast<long long>(A[index]) - line[size - 1];
long long diff2 = static_cast<long long>(line[size - 1]) - line[size - 2];
if (diff1 == diff2) {
line.push_back(A[index]);
DFS(A, index + 1, line, count);
line.pop_back();
}
}
// do not include A[index]
DFS(A, index + 1, line, count);
}
};
2、动态规划:
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.
思路:
1、回溯法:我开始自然而然地想到了回溯法,也就是每个元素我们试着将它加入等差数列中,看看是否符合要求,然后再将它取出来。最终统计出符合条件的等差数列的个数。然而却无法通过大数据测试,因为对于[1,1,1,1,1,1,1,1,1,1,1,1]这样的测试用例,回溯法会涉及到大量的重复计算。
2、动态规划:定义dp[index][diff]表示以A[index]结尾,等差值为diff的序列的个数,那么状态转移方程为dp[index][diff] = sum(dp[i][diff] + 1),其中0 <= i <= index - 1。注意sum内部+1是由于包含了A[index]本身。在实现中,由于以A[index]结尾的序列的diff个数可能是稀疏的, 所以我们采用vector<unordered_map<int,int>> 这种数据结构来表示dp。这种算法的时间复杂度是O(n^2),可以顺利通过大数据测试。
代码:
1、回溯法:
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& A) {
vector<int> line;
int count = 0;
DFS(A, 0, line, count);
return count;
}
private:
void DFS(vector<int> &A, int index, vector<int> &line, int &count) {
if (index == A.size()) {
if (line.size() >= 3) {
++count;
}
return;
}
// include A[index]
if (line.size() < 2) {
// include A[index]
line.push_back(A[index]);
DFS(A, index + 1, line, count);
line.pop_back();
}
else { // line.size() >= 2
// A[index] can be included
int size = line.size();
long long diff1 = static_cast<long long>(A[index]) - line[size - 1];
long long diff2 = static_cast<long long>(line[size - 1]) - line[size - 2];
if (diff1 == diff2) {
line.push_back(A[index]);
DFS(A, index + 1, line, count);
line.pop_back();
}
}
// do not include A[index]
DFS(A, index + 1, line, count);
}
};
2、动态规划:
class Solution { public: int numberOfArithmeticSlices(vector<int>& A) { if(A.empty()) { return 0; } vector<unordered_map<int,int>> dp(A.size()); //[index, [difference, count]] int res = 0; for(int i = 0; i < A.size(); ++i) { for(int j = 0; j < i; ++j) { if((long)A[i] - (long)A[j] > INT_MAX || (long)A[i] - (long)A[j] < INT_MIN) { continue; } int dif = A[i] - A[j]; dp[i][dif] += 1; if(dp[j].find(dif) != dp[j].end()) { dp[i][dif] += dp[j][dif]; res += dp[j][dif]; } } } return res; } };
相关文章推荐
- [Leetcode] 521. Longest Uncommon Subsequence I 解题报告
- [Leetcode] 522. Longest Uncommon Subsequence II 解题报告
- 【LeetCode】376.Wiggle Subsequence(Medium)解题报告
- 【LeetCode】674. Longest Continuous Increasing Subsequence 解题报告
- [Leetcode] 674. Longest Continuous Increasing Subsequence 解题报告
- leetcode解题报告:392. Is Subsequence
- 【LeetCode】521. Longest Uncommon Subsequence I 解题报告(Python)
- [leetcode]215. Kth Largest Element in an Array@Java解题报告
- 【LeetCode】47.Permutations II(Medium)解题报告
- Permutations [Leetcode 解题报告]
- 【LeetCode】667. Beautiful Arrangement II 解题报告(Python)
- [leetcode] 383. Ransom Note 解题报告
- [Leetcode] 12. Integer to Roman 解题报告
- LeetCode(1) Two Sum解题报告
- [leetcode] 45. Jump Game II 解题报告
- leetcode解题报告(8):Remove Element
- [Leetcode] 611. Valid Triangle Number 解题报告
- LeetCode 230. Kth Smallest Element in a BST 解题报告
- [LeetCode]406. Queue Reconstruction by Height 解题报告
- [Leetcode] 203. Remove Linked List Elements 解题报告