446等差数列划分II-子序列

题目:如果一个数列至少有三个元素,并且任意两个相邻元素之差相同,则称该数列为等差数列。例如,以下数列为等差数列:
1, 3, 5, 7, 9
7, 7, 7, 7
3, -1, -5, -9
以下数列不是等差数列。
1, 1, 2, 5, 7
数组 A 包含 N 个数,且索引从 0 开始。该数组子序列将划分为整数序列 (P0, P1, ..., Pk),P 与 Q 是整数且满足 0 ≤ P0 < P1 < ... < Pk < N。如果序列 A[P0],A[P1],...,A[Pk-1],A[Pk] 是等差的,那么数组 A 的子序列 (P0,P1,…,PK) 称为等差序列。值得注意的是,这意味着 k ≥ 2。函数要返回数组 A 中所有等差子序列的个数。输入包含 N 个整数。每个整数都在 -231 和 231-1 之间,另外 0 ≤ N ≤ 1000。保证输出小于 231-1。

来源:https://leetcode-cn.com/problems/arithmetic-slices-ii-subsequence/

法一:自己的代码   时间复杂度是(1 + n) * n / 2 即n方

思路:依次遍历A中的每个数,dp[i][k]表示以A[i]结尾公差为k(k != 0),长度至少为2的等差数列的个数-1,写dp转移方程之前,最重要的是要明确dp方程的定义。不同的dp转移方程直接决定了不同的方法。

from collections import defaultdict
from typing import List
class Solution:
    def numberOfArithmeticSlices(self, A: List[int]) -> int:
        size = len(A)
        # 注意这里,内部是个可变对象,不能直接乘,类似与[[0,1]] * 5这种,改一个就全改了
        # dp = [defaultdict(lambda: -1)] * size
        dp = []
        # 生成dp
        for i in range(size):
            dp.append(defaultdict(lambda: -1))
        ans = 0
        for i in range(1,size):
            # m是为了记录公差为0的等差数列的长度
            m = 1
            for j in range(i):
                # k是公差
                k = A[i] - A[j]
                # 如果公差存在于以A[j]结尾的数列中,且公差不为0,则必定可以构成长为3的等差数列
                if k in dp[j].keys():
                    if k != 0:
                        # 这两行是关键,
                        # 注意这里的两个1,第一个1是为了补上dp[j][k]中从-1到0的那一次,同ans = ans + dp[j][k] + 1中的这个1
                        # 第二个1表示由A[j] A[i]构成的数列,同下面m +=1的这个1
                        dp[i][k] = (dp[j][k] + 1) +1 + dp[i][k]
                        # 加1是因为,初始值是从-1开始加的,如2:0表示公差为2,但它是长度为2的等差数列,
                        # 所以加1是为了抵消从-1加1到0的那一次,因为它已经构成了长度为2的等差数列,只不过以前长度无法达到3,现在达到了
                        # 这里之所以分开写是因为,dp[i][k]表示的是  以A[i]结尾的长度为2的等差数列的个数-1  所以dp[j][k]+1就是在A[j]后
                        # 添加A[i]后,以A[j] A[i]结尾的等差数列的个数
                        ans = ans + dp[j][k] + 1
                    else:
                        m += 1
                else:
                    dp[i][k] += 1
            # 如果有公差为0的数列无法使用上述方法,直接记录数列的长度用归纳法求解
            ans += (2 ** m - (m+1))
        # for i in dp:
        #     print(i)
        print(len(A), len(set(A)))
        return ans
if __name__  == '__main__':
    duixiang = Solution()
    # a = duixiang.numberOfArithmeticSlices([1,1,1,1,1])
    # a = duixiang.numberOfArithmeticSlices([79,20,64,28,67,81,60,58,97,85,92,96,82,89,46,50,15,
    #                                            2,36,44,54,2,90,37,7,79,26,40,34,67,64,28,60,89,46,
    #                                            31,9,95,43,19,47,64,48,95,80,31,47,19,72,99,28,46,
    #                                            13,9,64,4,68,74,50,28,69,94,93,3,80,78,23,80,43,49,
    #                                            77,18,68,28,13,61,34,44,80,70,55,85,0,37,93,40,47,
    #                                            47,45,23,26,74,45,67,34,20,33,71,48,96])
    # a = duixiang.numberOfArithmeticSlices([2,2,-1,2,5,8])
    # a = duixiang.numberOfArithmeticSlices([1,2,3,4,5])
    # a = duixiang.numberOfArithmeticSlices([6,6,8,10])
    a = duixiang.numberOfArithmeticSlices([4,4,3,4,5,6])
    # a = duixiang.numberOfArithmeticSlices([3,4,5,6,7])
    print(a)
View Code
原文地址:https://www.cnblogs.com/xxswkl/p/12295923.html