01-学生出勤记录

学生出勤记录II

给定一个正整数 n,返回长度为 n 的所有可被视为可奖励的出勤记录的数量。 答案可能非常大,你只需返回结果mod 109 + 7的值。

学生出勤记录是只包含以下三个字符的字符串:

‘A’ : Absent,缺勤
‘L’ : Late,迟到
‘P’ : Present,到场
如果记录不包含多于一个’A’(缺勤)或超过两个连续的’L’(迟到),则该记录被视为可奖励的。

思路(递归->动态规划)

首先,假设字符串只包含字符 L L L P P P A A A 产生的影响放在后面考虑。
假设 f [ n ] f[n] f[n] 表示长度为 n n n 的可奖励字符串的数目(只包含字母 L L L P P P)。下图说明计算 f [ n ] f[n] f[n] 的过程:

在这里插入图片描述
上图解释了如何将长度为 n n n 的可奖励字符串拆成结尾是 L L L或者 P P P 的长度为 n − 1 n-1 n1 的 2 个字符串。如果长度为 n − 1 n-1 n1 的字符串是可奖励的,那么将 P P P 接在这个字符串后面,得到长度为 n n n 的字符串,一定也是可奖励的。因此,每一个长度为 n − 1 n-1 n1 的字符串后面接上 P P P 都可以对应一个长度为 n n n 的字符串,这使得 f [ n − 1 ] f[n-1] f[n1] f [ n ] f[n] f[n] 可以产生贡献。

对于以 L L L 结尾的字符串,是否可奖励取决于对应的长度为 n − 3 n-3 n3 的字符串。所以我们需要考虑所有长度为 n − 3 n-3 n3 的可奖励字符串。在 4 种可能的组合中,第四种也就是以 L L LL LL 开始的会导致一个不可奖励字符串。由于我们在考虑长度为 n − 3 n-3 n3 的可奖励字符串,为了避免在 n − 1 n-1 n1 的时候已经是不可奖励的,第四种情况的不可奖励数目,可认为是长度为 n − 4 n-4 n4 的字符串必须以 P P P 结尾对应的奖励数目。

所以除了在长度为 n − 4 n-4 n4 的可奖励字符串后面的 P L L PLL PLL ,其他所有长度为 n − 1 n-1 n1 的可奖励字符串都可以对长度为 n n n 的可奖励字符串做出贡献。所以 f [ n − 1 ] − f [ n − 4 ] f[n-1] - f[n-4] f[n1]f[n4] 会对 f [ n ] f[n] f[n] 产生贡献。

所以,递归表达式为:
f [ n ] = 2 f [ n − 1 ] − f [ n − 4 ] f[n] = 2f[n-1] - f[n-4] f[n]=2f[n1]f[n4]

现在,我们需要考虑加入字符 A A A 造成的影响。我们知道最多可以将 1 个 A A A 放入一个可奖励字符串中,所以我们考虑如下两种情况:
1、没有 A A A:可奖励字符串数目就是 f [ n ] f[n] f[n];
2、有一个 A A A:这个 A A A 可能出现在 n n n 个位置中的任何一个位置。如果 A A A 出现在字符串的位置 i i i, 可奖励字符串的总数为: ∑ i = 1 n ( f [ i − 1 ] ∗ f [ n − i ] ) \sum_{i=1}^{n} (f[i-1] * f[n-i]) i=1n(f[i1]f[ni]).

代码(动态规划)

我们每次计算 f [ i ] f[i] f[i] 都需要使用递归函数,直到走到字符串最开始的位置。如果我们使用记录下来的 f [ j ] f[j] f[j] 去更新 f [ i ] f[i] f[i],我们可以节省非常大量的计算时间.

class Solution:
    
    def checkRecord(self, n: int) -> int:
        f = [1,2,4,7]
        
        for i in range(4,n+1):
            f.append(((2*f[i-1])%1000000007+ (1000000007-f[i-4]))%1000000007)
        sum = f[n]
        
        for i in range(1,n+1):
            
            sum += (f[i-1] * f[n-i])%1000000007
            
        return sum%1000000007
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值