这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战
今天一上班就开始摸鱼,惯例每日一题算法(平时不发是因为平时的题不会),今天力扣的每日一题是中等题,看着好像能做出来。
题目
如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。
- 例如,[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。 给你一个整数数组 nums ,返回数组 nums 中所有为等差数组的 子数组 个数。
子数组 是数组中的一个连续序列。
示例一
输入: nums = [1,2,3,4]
输出: 3
解释: nums 中有三个子等差数组:[1, 2, 3]、[2, 3, 4] 和 [1,2,3,4] 自身。
示例二
输入: nums = [1]
输出: 0
逻辑思路
- 等差数列:相邻的两个参数的差相等,公式:d = a(n) - a(n-1)
- 极端校验:数组长度小于3
- 看到这道题,第一想法是动态规划(薄弱的算法领域里面最熟悉的)
- 单个:判断当前数据是否能与前面两个数据形成新的等差数列(最小单位:三个)
- 整体数组:判断当前数据,与前面的等差数列能否形成大型的等差数列
- 统计数据:new 一个数组,指针所向则为当前最多子数组个数
实现
class Solution {
//判断一个数组是否等差,我们采用动态规划去做
public int numberOfArithmeticSlices(int[] nums) {
//dp[n]代表从零到n具有的等差数据个数
int len=nums.length;
if(len<3) return 0;
int[] dp=new int[len+1];
//确定初始值
if(nums[1]-nums[0]==nums[2]-nums[1]) dp[3]=1;
for(int i=2;i<len-1;i++){
//如果有新的元素加进来,我们要做以下判断,如果可以和之前元素等差,那么结果加一,不然不进行改变
//同时要判断判断元素是否可以和以前的等差数组是否可以等差,可以的话继续加
if(nums[i+1]-nums[i]==nums[i]-nums[i-1]){
int count=1;
//在这里进行第二次for循环判断,得到新元素对于之前等差数列的影响
for(int j=i;j>1;j--){
if(nums[j]-nums[j-1]==nums[j-1]-nums[j-2]){
count++;
}
else break;
}
dp[i+2]=dp[i+1]+count;
}
else dp[i+2]=dp[i+1];
}
return dp[len];
}
优化
虽然说实现是实现了,但是相对来说时间复杂度太高,光是判断等差就需要两个for循环,O(n²)+初始值;优化的空间很大,特别是用动态规划的话,第二次for循环的判断和初始值可以修改优化
class Solution {
public int numberOfArithmeticSlices(int[] nums) {
int length = nums.length;
if (length<3){
return 0;
}
int d = nums[1]-nums[0];
int t =0,ans =0;
for (int i = 2;i<length;++i){
if (nums[i]-nums[i-1] == d){
++t;
}else {
d= nums[i]-nums[i-1];
t =0;
}
ans +=t;
}
return ans;
}
}
复杂度分析
- 时间复杂度:O(n)O(n),其中 nn 是数组 nums 的长度。
- 空间复杂度:O(1)O(1)。