Leetcode 552. Student Attendance Record II

Problem:

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 109 + 7.

A student attendance record is a string that only contains the following three characters:

 

  1. 'A' : Absent.
  2. 'L' : Late.
  3. '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).

Example 1:

Input: n = 2
Output: 8 
Explanation:
There are 8 records with length 2 will be regarded as rewardable:
"PP" , "AP", "PA", "LP", "PL", "AL", "LA", "LL"
Only "AA" won't be regarded as rewardable owing to more than one absent times. 

Note: The value of n won't exceed 100,000.

 

Solution:

  这道题先说说我的做法吧(貌似我自己想出来的解法效率都不高。。。),首先这道题肯定用动态规划,他有两个约束条件,先来处理第一个条件,是否存在缺席,因此我维护了两个数组,hasAbsent表示存在一次缺席的情况下分别以A,L,P结尾的可能性数量,noAbsent表示不存在缺席的情况下以L,P结尾的可能性数量

1. 对于hasAbsent[i][0],即存在缺席以A结尾的数量等于noAbsent[i-1][0]+noAbsent[i-1][1]加上最后一个A

2. 对于hasAbsent[i][1],即存在缺席以L结尾的数量可以分五种情况

  (1)若i-2之前存在缺席,则有...A_L;...L_L;...P_L这三种可能性,第一种下划线处可以填P,L,第二种下划线只能填P,第三种下划线可以填P,L。

  (2)若i-2之前不存在缺席,则有...LAL;...PAL这两种可能,

 因此hasAbsent[i][1] = (hasAbsent[i-2][0]*2+hasAbsent[i-2][1]+hasAbsent[i-2][2]*2+noAbsent[i-2][0]+noAbsent[i-2][1])%MOD;

3.对于hasAbsent[i][2],即存在缺席以P结尾的数量等于i-1之前存在缺席的所有情况加上结尾的P,

4.对于noAbsent[i][0],即不存在缺席以L结尾的数量分两种情况,...L_L;...P_L,第一种情况下划线可以填P,第二种下划线可以填L,P,所以noAbsent[i][0] = (noAbsent[i-2][0]+noAbsent[i-2][1]*2)%MOD;

5.对于noAbsent[i][1],即不存在缺席以P结尾的数量等于i-1时所有不存在缺席的可能性之和。

代码如下,时间复杂度为O(n),能够AC,但是效率不高,原因在于乘法和加法运算有点多。

 1 class Solution {
 2 public:
 3     int checkRecord(int n) {
 4         int MOD = 1000000007;
 5         vector<vector<int64_t>> hasAbsent(n,vector<int64_t>(3,0));
 6         vector<vector<int64_t>> noAbsent(n,vector<int64_t>(2,0));
 7         if(n == 1) return 3;
 8         if(n == 2) return 8;
 9         hasAbsent[0] = {1,0,0};
10         noAbsent[0] = {1,1};
11         hasAbsent[1] = {2,1,1};
12         noAbsent[1] = {2,2};
13         for(int i = 2;i != n;++i){
14             hasAbsent[i][0] = (noAbsent[i-1][0]+noAbsent[i-1][1])%MOD;
15             hasAbsent[i][1] = (hasAbsent[i-2][0]*2+hasAbsent[i-2][1]+hasAbsent[i-2][2]*2+noAbsent[i-2][0]+noAbsent[i-2][1])%MOD;
16             hasAbsent[i][2] = (hasAbsent[i-1][0]+hasAbsent[i-1][1]+hasAbsent[i-1][2])%MOD;
17             noAbsent[i][0] = (noAbsent[i-2][0]+noAbsent[i-2][1]*2)%MOD;
18             noAbsent[i][1] = (noAbsent[i-1][0]+noAbsent[i-1][1])%MOD;
19         }
20         return (hasAbsent[n-1][0]+hasAbsent[n-1][1]+hasAbsent[n-1][2]+noAbsent[n-1][0]+noAbsent[n-1][1])%MOD;
21     }
22 };

  接下来看一种思路非常清晰,效率又非常高的解法,参考这里。解释下他在做什么,P[i]记录了以P结尾不存在A的在i处结尾的可能性,PorL[i]记录了以P或L结尾i的不存在A的在i处结尾的可能性,很显然,对于PorL[i],存在三种情况,...P;...PL;...PLL,因此PorL[i] = (P[i] + P[i - 1] + P[i - 2])。接下来需要对PorL数组进行处理,我们在任意位置用A进行替换,那么可能性之和即左右两部分的长度的可能性之积,即PorL[i] * PorL[n - 1 - i]

Code:

 

class Solution {
public:
    int checkRecord(int n) {
        int M = 1000000007;
        vector<long long> P(n + 1), PorL(n + 1);
        P[0] = 1; PorL[0] = 1; PorL[1] = 2;
        for (int i = 1; i <= n; ++i) {
            P[i] = PorL[i - 1];
            if (i > 1) PorL[i] = (P[i] + P[i - 1] + P[i - 2]) % M;
        }
        long long res = PorL[n];
        for (int i = 0; i < n; ++i) {
            long long t = (PorL[i] * PorL[n - 1 - i]) % M;
            res = (res + t) % M;
        }
        return res;
    }
};

 

posted on 2019-01-11 06:52  周浩炜  阅读(405)  评论(0编辑  收藏  举报

导航