leetcode - 552. Student Attendance Record II

算法系列博客之Dynamic Programming

动态规划是和贪心算法比较相似的一种算法策略
      很多时候它们一般都遵从于某种线性的策略,使得整个逻辑和复杂度都看上去是线性的
但其二者有着本质的区别
      动态规划实际上是在划分子问题,子问题可以用同种方法进行再度拆解,凑巧划分的过程大多数时候是线性的
      而贪心算法则是解决问题的步骤看似是一个线性过程,但每一步可以看作一个原子操作,不可拆解

本篇博客将运用动态规划的思想来解决leetcode上552号问题


问题描述:

Given a positive integer n, return the number of all possible attendance records with length n, which will be regarded as rewardable. The answer may be very large, return it after mod 10^9 + 7.

A student attendance record is a string that only contains the following three characters:
     ‘A’: Absent.
     ‘L’ : Late.
     ‘P’ : Present.
A record is regarded as rewardable if it doesn’t contain more than one ‘A’ (absent) or more than two continuous ‘L’ (late).

题目的模型大致符合典型的线性求解思路,因而可以尝试找出长度为n的解与长度为n-1,n-2等的依赖关系
题目中看似有三种字母可选,但是A和L都是有限制的

A最多只能够出现一个,那么整个寻求答案的逻辑中就只有两中可能:有1个A 或 无A

  • 有一个A的时候,A的位置只能有n种,而其左侧和右侧的两个子串中就一定不会有A
    可能的结果数也就等于左侧结果乘以右侧结果,问题转化为无A情况的求解
  • 无A的时候,假设poss[i] 表示 长度为 i 没有A的可能结果数
    现在只需考虑L和P,显然从有限制条件的L入手会比较方便,恰巧这个限制给我们提供了线性依赖关系
    即使得长度为i 的串只可能有以下几种结尾方式:
          ·   以 P    结尾:这种情况的可能数等于poss[i-1]
          ·   以 PL  结尾:这种情况的可能数等于poss[i-2]
          ·   以 PLL 结尾:这种情况的可能数等于poss[i-3]
    从而poss[i] = poss[i-1] + poss[i-2] + poss[i-3]
    得到的这个递推式表示至少需要定义三个边界值poss[1] = 2, poss[2] = 4
    余下的边界值考虑定义poss[0]还是poss[3]:
    长度为3,以PLL结尾的可能数为1,对应poss[0], 因而定义poss[0]是有意义的,此外以0作为起始点额更加与计算机本身的特性贴合

回顾这个过程,当抛开A的影响之后,整个思路就变得非常的明朗清晰
而整个思路历程也已经严谨的证明了这个算法的正确性和可行性
基于此再来实现代码也好似非常的容易了

class Solution(object):
    def checkRecord(self, n):
        if n == 1:
            return 3

        poss = [1, 2, 4]
        for i in range(2, n):
            poss.append((poss[i] + poss[i-1] + poss[i-2]) % 1000000007)
        res = poss[n]
        for i in range(n):
            res = (res + poss[i] * poss[n-i-1]) % 1000000007
        return res

时间复杂度分析,两次并行关系的规模为n的循环,循环内部常数规模指令,因而O(n)
空间复杂度分析,空间上,用到了规模为n的数组,因而也为O(n)
实际上,得到的递推式很多时候还可以通过数学方法归纳为一个表达式,从而得到O(1)的高效率算法
但是,就这个题而言,因为还需要计算有一个A的情况,所以需要存储poss数组,也就必然需要进行线性循环了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值