【动态规划】力扣413:等差数列划分

如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。
例如,[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] 自身。

  1. 双指针
    等差数列的所有的相邻数字的差 d 是固定的。如果我们已经知道一个子数组的前面部分不是等差数列以后,那么后面部分就不用判断了。
    因此,对于每个起始位置,只需要向后进行一遍扫描,直到不再构成等差数列为止,此时已经没有必要再向后扫描。
    这个思路其实就是双指针(滑动窗口) 的解法。
    image

作者:fuxuemingzhu
链接:https://leetcode-cn.com/problems/arithmetic-slices/solution/fu-xue-ming-zhu-bao-li-shuang-zhi-zhen-d-fc1l/

  1. 动态规划
    定义 dp[i] 是以 A[i] 为终点的等差数列的个数
  • A[i] - A[i - 1] == A[i - 1] - A[i - 2]时,说明增加的A[i]能和前面构成等差数列,那么 dp[i] = dp[i - 1] + 1;
  • A[i] - A[i - 1] != A[i - 1] - A[i - 2]时, 说明增加的 A[i]不能和前面构成等差数列,所以dp[i] = 0。
    因此初始化dp[]元素均为 0 ,要求的是整个数组中的等差数列的数目,所以需要把 0 <= i <= len(A - 1) 的所有 dp[i] 的结果累加起来。
class Solution:
    def numberOfArithmeticSlices(self, nums: List[int]) -> int:
        n = len(nums)
        if n < 3:
            return 0
        dp = [0] * n
        for i in range(2, n):
            if(nums[i] - nums[i-1] == nums[i - 1] - nums[i - 2]):
                dp[i] = dp[i - 1] + 1
        return sum(dp)

时间复杂度:O(N);
空间复杂度:O(N)。

  1. 动态规划优化
    由于 dp[i] 只和 dp[i - 1] 有关,所以可以进行状态压缩,只用一个变量 k 来表示以 A[i] 为终点的等差数列的个数。
class Solution:
    def numberOfArithmeticSlices(self, nums: List[int]) -> int:
        n = len(nums)
        count, ans = 0, 0 # count计数当终点为i时的等差数列数,ans为所有的
        for i in range(2, n):
            if(nums[i] - nums[i-1] == nums[i - 1] - nums[i - 2]):
                count += 1
                ans += count
            else:
                count = 0
        return ans

时间复杂度:O(N);
空间复杂度:O(1)。

posted @   Vonos  阅读(71)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示