题目 等差数列划分
如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。
例如,[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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/arithmetic-slices
思路
做动态规划的题目练习碰到的题目,乍一看是动归,但其实不难找到这样的规律:
输入:nums = [1,2,3]
输出:1
输入:nums = [1,2,3,4]
输出:3
输入:nums = [1,2,3,4,5]
输出:6
可以看出,3个连续的等差数可以得到1个等差数组,4个可以得到1+2个等差数组,5个可以得到1+2+3个等差数组。
那么很简单可以得到通项公式:n个连续的等差数可以得到
(n-2)(n-1)/2
个等差数组。
那么接下来不难猜到,我们可以使用双指针进行求解,从左指针开始,右指针依次往后探测下一个数是否和前面的数构成等差。举个下面的例子:
输入:nums = [1,2,3,4,9,11,13]
左指针在1,以2-1=1作为等差向后探测,右指针一直到4都满足条件,指向9的时候发现不满足了,此时计算左右指针下标,并带入前面的公式,得到有3个等差数组。
然后把左指针移到9的前一位4,以9-4=5再次寻找下一个等差数组。结果发现右指针指向11并不满足,此时得到0个等差数组。
把左指针移到11的前一位9,以11-9=2再次寻找下一个等差数组,并最终再得到1个等差数组。
总结一下,该方法只需要遍历一次数组,时间复杂度绝对的O(n),存储空间只需要三个变量,空间复杂度O(1)。
代码
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& nums) {
if (nums.size() < 3) {
return 0;
}
int left = 0;
int right = 1;
int minus = nums[right] - nums[left];
int length = nums.size();
++right;
int answer = 0;
while (right < length) {
if (nums[right] - nums[right - 1] != minus) {
int n = right - left;
if (n > 2) {
answer += ((n - 2) * (n - 1) / 2);
}
left = right - 1;
minus = nums[right] - nums[left];
}
++right;
}
int n = right - left;
if (n > 2) {
answer += ((n - 2) * (n - 1) / 2);
}
return answer;
}
};
有点奇怪为什么O(1)复杂度的空间只到了33.59%,时间倒是0ms,100%。