413.等差数列划分
题目:
如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。
例如,[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。
给你一个整数数组 nums ,返回数组 nums 中所有为等差数组的 子数组 个数。
子数组 是数组中的一个连续序列。
示例 1:
输入:nums = [1,2,3,4]
输出:3
解释:nums 中有三个子等差数组:[1, 2, 3]、[2, 3, 4] 和 [1,2,3,4] 自身。
示例 2:
输入:nums = [1]
输出:0
解法一 动态规划
动态规划重要几点:(1) dp[i]的定义;(2)状态;(3)选择;
dp[i]的定义:表示第i个元素包括第i个元素之前的所有等差数列。
状态:选择了这个元素,可以组成更长的等差数组。或者选择了这个元素,不能组成更长的等差数组。
选择:只能选择下一个。
所以动态规划的方程为:
dp[i] = dp[i-1]+1 //如果能组成更长的等差数组
dp[i] = 0 //如果组不成更长的等差数组
如果能组成更长的等差数组:那么num[i]-num[i-1] == num[i-1]-num[i-2]
否则的话不能组成。所以动态规划方程就出来了。
需要注意的是,一般情况下,在开始动态规划的时候,需要定义初始状态,这道题中初始状态都是0,所以可以直接去掉。具体看代码提示。
代码
class Solution {
public int numberOfArithmeticSlices(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
//这里应该有初始状态.即dp[0]=dp[1]=dp[2] = 0,可以不用罗列,具体原因:
//在定义数组的时候,基本类型的数组初始化为零值.int的话为0,boolean的话是false。
for (int i = 2; i < n; i++) {
if (nums[i]-nums[i-1] == nums[i-1]-nums[i-2]){
dp[i] = dp[i-1]+1;
}else {
dp[i] = 0;
}
}
return Arrays.stream(dp).sum();
}
}
解法二:查分+计数
leetcode的官方题解。
感觉讲的太复杂了,代码其实挺简单的。
public int numberOfArithmeticSlices(int[] nums) {
int n = nums.length;
if (n == 1) {
return 0;
}
int d = nums[0] - nums[1], t = 0;
int ans = 0;
//因为等差数列的长度至少为3,所以可以从i=2开始枚举
for (int i = 2; i < n; i++) {
if (nums[i-1] - nums[i] == d){
++t;
}else{
d = nums[i-1] - nums[i];
t= 0;
}
ans+=t;
}
return ans;
}
就是在循环数组中的每个数,多设置一个重置位,当不满足等差定义的时候,将重置位置为0,否则的话重置位++,每次循环把重置位和ans相加即可。