1. 程式人生 > 其它 >【動態規劃】力扣413:等差數列劃分

【動態規劃】力扣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 是固定的。如果我們已經知道一個子陣列的前面部分不是等差數列以後,那麼後面部分就不用判斷了。
    因此,對於每個起始位置,只需要向後進行一遍掃描,直到不再構成等差數列為止,此時已經沒有必要再向後掃描。
    這個思路其實就是雙指標(滑動視窗) 的解法。

作者: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)。