每日一解 看似动归实则找规律 等差数列划分

题目 等差数列划分

如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。

例如,[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%。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值