https://leetcode-cn.com/problems/arithmetic-slices/
动态规划,dp[i]的含义是以nums[i]结尾的等差数列的个数
则假设nums.size() == 6的话,那么所有的等差字数个数就等于以nums[2] nums[3] nums[4] nums[5]为结尾的等差子数列的个数求和。
比如 nums = [1, 2, 3, 4, 5, 6]
则以nums[2] = 3结尾的等差数列个数dp[2] = 1,即 1 2 3
以nums[3] = 4结尾的等差数列的个数dp[3] = dp[2] + 1 = 2,即 2 3 4 和1 2 3 4,所以为什么当新的nums[i]能与其前两两个数都成等差数列的时候,则以nums[i]结尾的等差子数列个数比以nums[i -1]结尾的等差子数列的个数多1呢?因为nums[i]能与前边两个数构成等差数列,则对于所有以
nums[i - 1]结尾的等差数列而言,在其后边接上一个nums[i],即nums[i - 1] 结尾的所有等差数列都一一对应了一个长度加了1的以nums[i]结尾的等差数列,而nums[i]结尾比nums[i-1]结尾多出来的那个等差数列是 nums[i] nums[i - 1] nums[i - 2], 因为这个数列,在nums[i - 2]结尾的数列中是没有对应的,因为规定了等差数列长度不小于3. 因此在nums[i - 1]结尾的数列中只有两个元素是构不成等差数列的。
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& nums) {
// dp[i]的含义是以nums[i]结尾的等差子数列的个数
/*
比如nums = [1, 2, 3, 4, 5]
那么以3结尾的等差数列个数dp[2] = 1 即 1 2 3
以4结尾的等差数列个数 dp[3] = 2, 即 2 3 4 1 2 3 4
然后把所有dp[i]累加起来就是所有的等差子数组
*/
int len = nums.size();
if(len < 3) return 0;
// 开状态数组
vector<int> dp(len);
dp[0] = 0; // 这里其实不用,前边dp已经默认值 初始化了
dp[1] = 0;
int ans = 0;
for(int i = 2; i < len; ++i){
if(nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2]){
dp[i] = dp[i - 1] + 1;
ans += dp[i];
}
}
return ans;
}
};
上边动态规划开了个数组,但实际上也可以不用,只要每个等差子序列的时候把所有的dp累加起来,当遇到一个给等差的元素的时候,将dp归零即可。
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& nums) {
// dp[i]的含义是以nums[i]结尾的等差子数列的个数
/*
比如nums = [1, 2, 3, 4, 5]
那么以3结尾的等差数列个数dp[2] = 1 即 1 2 3
以4结尾的等差数列个数 dp[3] = 2, 即 2 3 4 1 2 3 4
然后把所有dp[i]累加起来就是所有的等差子数组
*/
int len = nums.size();
if(len < 3) return 0;
// 开状态数组
// vector<int> dp(len);
// dp[0] = 0; // 这里其实不用,前边dp已经默认值 初始化了
// dp[1] = 0;
int dp = 0;
int ans = 0;
for(int i = 2; i < len; ++i){
if(nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2]){
dp = dp + 1;
ans += dp;
}else{
dp = 0;
}
}
return ans;
}
};