持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情
力扣——413. 等差数列划分
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] 自身。
-
提示:
1 <= nums.length <= 5000-1000 <= nums[i] <= 1000
问题解析
暴力做法
我们知道,一个长为n的数组,它最多会有:n+(n-1)+(n-2)+……+(n-n+1)=n*(n+1)/2个子数组。那么我们可以在O(n^2)的时间复杂度下枚举全部的子数组,再判断这些子数组是否是等差数组即可。
时间复杂度:O(n^3).
//按理说这代码应该过不了,但是却能AC,很怪
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& nums) {
int n=nums.size(),cnt=0;
//枚举数组长度
for(int len=3;len<=n;len++)
{
//枚举子数组左端点
for(int i=0;i<=n-len;i++)
{
bool flag=true;
//数组右端点
int j=i+len-1;
//公差
int d=nums[i+1]-nums[i];
for(int k=i+2;k<=j;k++)
{
//如果有两个数的差不等于我们之前算出的公差,那他们就不是等差数列
if(nums[k]-nums[k-1]!=d)
{
flag=false;
break;
}
}
if(flag)cnt++;
}
}
return cnt;
}
};
O(n^3)的复杂度太高了,我们想办法进行优化。
就像我们上面说的,一个长为n的数组能枚举出n*(n+1)/2个子数组。而且根据等差数列和子数组的性质,如果这个数组是等差数列,那么它的所有子数组都是等差数列。那么我们直接找出每一段最长的等差数组,然后就可以直接算出有多少个子数组也是等差数组了。
(题目说了,至少长度为3才能成为等差数列,所有结果数应该是:(n-2)+(n-3)+……+(n-n+1)。)
现在要做的就是找到每一段最长的等差数组,我们可以用滑动窗口来作,初始先用两个数算出公差,之后滑窗右端点移动,如果新进来的数和它前一个数的差等于公差,滑窗长度+1。如果不相等,那么滑窗里的数就是这一段最长的等差数组了,此时根据滑动窗口的长度计算结果数,然后更新公差,继续找下一段等差数组即可。 时间复杂度:O(n);
AC代码
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& nums) {
if(nums.size()<3)return 0;
int n=nums.size(),cnt=0;
int len=2,d=nums[1]-nums[0];
for(int i=2;i<n;i++)
{
if(nums[i]-nums[i-1]==d)
{
len++;
}
else
{
cnt+=len*(len+1)/2-len*2+1;
len=2;
d = nums[i] - nums[i - 1];
}
}
cnt+=len*(len+1)/2-len*2+1;
return cnt;
}
};