【解析】使用状态机解决LeetCode552. 学生出勤记录 II

题目:

可以用字符串表示一个学生的出勤记录,其中的每个字符用来标记当天的出勤情况(缺勤、迟到、到场)。记录中只含下面三种字符:
'A':Absent,缺勤
'L':Late,迟到
'P':Present,到场
如果学生能够 同时 满足下面两个条件,则可以获得出勤奖励:

按总出勤计,学生缺勤('A')严格 少于两天。
学生 不会 存在 连续 3 天或 连续 3 天以上的迟到('L')记录。
给你一个整数 n ,表示出勤记录的长度(次数)。请你返回记录长度为 n 时,可能获得出勤奖励的记录情况 数量 。答案可能很大,所以返回对 109 + 7 取余 的结果。

示例 1:

输入:n = 2
输出:8
解释:
有 8 种长度为 2 的记录将被视为可奖励:
"PP" , "AP", "PA", "LP", "PL", "AL", "LA", "LL" 
只有"AA"不会被视为可奖励,因为缺勤次数为 2 次(需要少于 2 次)。
示例 2:

输入:n = 1
输出:3
示例 3:

输入:n = 10101
输出:183236316

题目解析:


首先,我们需要知道,出勤记录是由'A','L','P'三个字符组成的字符串,字符'A'的总数要小于2,连续出现的字符'L'需要小于三个,我们需要计算固定长度的出勤记录满足这两个条件的情况个数。

而对于这种三个字符的字符串组成情况个数问题,得到的结果一般都很大,直接使用count(A)之类的判断肯定是满足不了性能需求的,所以我们首先考虑的是动态规划来实现每一个动态规划的部分都不会连续出现三个'L'字符,这里可以构建一个状态机来实现题目的模拟:
首先,字符串子部分可以是没有A,也没有L的,我们统计的初始值就是这种情况,是空的,所以可以记为状态1。
其次是第二种情况,在字符串子部分没有A,但有一个L。
第三种情况是没有A,有两个L。
第四种情况是有一个A,没有L。
第五种情况是有一个A,有一个L。
第六种情况是有一个A,有两个L。
而初始的情况除了第一种情况之外都是没有出现的,所以这几种情况的初始值为(1,0,0,0,0,0),
假如我们把这六种情况设为a,b,c,d,e,f。
那么这六种状态之间的转变为:
第一种可以变为第二种,加一个L。
第二种可以变为第三种,加一个L。

第四种可以变为第五种,加一个L。
第五种可以变为第六种,加一个L。

而第一种和第四种之间,加一个A,也可以转换过去。
所以在这几种状态之间添加剩下的字符P,第一种状态会受到第二种和第三种状态的影响,第四种状态会受到第五种和第六种状态的影响,而第四种状态还会受到第一种状态的影响。

所以状态的动态变化过程为(a,b,e,d,e,f)=(a+b+c,a,b,a+b+c+d+e+f,d,e)。
那么我们剩下的工作就是将状态的动态变化过程代入到循环中。

def checkRecord(self, n):
        """
        :type n: int
        :rtype: int
        count(A)<2
        current_L<3
        n,situation(ALP)
        result%(10**9+7)
        """
        a,b,c,d,e,f=1,0,0,0,0,0
        for i in range (n):
            a,b,c,d,e,f=a+b+c,a,b,a+b+c+d+e+f,d,e
            a%=(10**9+7)
            b%=(10**9+7)
            c%=(10**9+7)
            d%=(10**9+7)
            e%=(10**9+7)
            f%=(10**9+7)
        return (a+b+c+d+e+f)%(10**9+7)


至此,这道题目就已经完成了。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值