LeetCode Week17: Student Attendace Record II

来源:互联网 发布:卡通农场数据 编辑:程序博客网 时间:2024/05/16 23:57

这一周完成的是Student Attendance Record系列的题目,其中第一题是关于string的使用,这里不再详细介绍其内容,第二题是关于Dynamic Programming的题目,本次题解将介绍第二题的解答过程。

题目

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:

‘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).

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.

我的分析

这道题与A的出现次数以及连续L的情况有关,考虑到使用动态规划求解,最开始是想用一个列数为3的二维数组来表示长度为n时各个变量结尾的可能情况数,后来发现这样没有办法对A出现的次数以及L的次数统计,遂改用三维数组,且因为在原序列中加入P不影响序列的可靠性,所以不需要做过多的考虑。

假设dp[n][i][j]表示长度为n的序列中,A出现了i次,以j个连续L结尾,现在来分析要如何构建这个矩阵:

  1. 不含A,不以L结尾的情况: tmp_dp[n][0][0] = sumhelper(dp[n-1][0])% 109+7; 即第一行的元素求和,表示前面不含A,可以没有/存在一个/存在两个L,然后当前加入的不是L也不是A的情况;

  2. 不含A,以一个L结尾的情况: tmp_dp[0][1] = dp[0][0]; 即表示在没有存在一个A且在以一个L结尾的序列上加入一个L;

  3. 不含A,以两个L结尾的情况: tmp_dp[0][2] = dp[0][1]; 即表示在没有存在一个A且已经有一个L结尾的序列上加入一个L;

  4. 含A,不以L结尾的情况,A是之前就有的或者A是刚刚加入: tmp_dp[1][0] = sumhelper(dp,2,3) % 109+7;

  5. 含A,以一个L结尾的情况: tmp_dp[1][1] = dp[1][0]; 即表示在存在一个A且在以一个L结尾的序列上加入一个L;

  6. 含A,以两个L结尾的情况: tmp_dp[1][2] = dp[1][1]; 即表示在存在一个A且已经有一个L结尾的序列上加入一个L;

其中sumhelper()是对一个长度为3的数组求和。最终的答案是将所有的情况加起来即可。(注意要对109+7取模

考虑到dp[n]仅仅只跟dp[n-1]有关,这里使用滚动数组,用二维数组表示dp。

代码

class Solution {public:    int sumhelper(int nums[]) {        long ans = 0;        for (int i = 0; i < 3; i ++)            ans += nums[i];        return ans % 1000000007;    }    int checkRecord(int n) {        int mod = 1000000007;        int dp[2][3] = {{1,1,0},{1,0,0}};        int tmp_dp[2][3] = {0};        for(int i = 2; i <= n; ++i)        {            // 逐一更新            // 不含A,不以L结尾的情况            tmp_dp[0][0] = sumhelper(dp[0]) % mod;            // 不含A,以一个L结尾的情况            tmp_dp[0][1] = dp[0][0];            // 不含A,以两个L结尾的情况            tmp_dp[0][2] = dp[0][1];            // 含A,不以L结尾的情况,A是之前就有的或者A是刚刚加入            tmp_dp[1][0] = (sumhelper(dp[0])+sumhelper(dp[1])) % mod;            // 含A,以一个L结尾的情况            tmp_dp[1][1] = dp[1][0];            // 含A,以两个L结尾的情况            tmp_dp[1][2] = dp[1][1];            tmp_dp[0][0] = sum(dp[0]);             tmp_dp[0][1] = dp[0][0];             tmp_dp[0][2] = dp[0][1];            tmp_dp[1][0] = (sum(dp[0]) + sum(dp[1])) % mod;            dp[0][0] = tmp_dp[0][0];  dp[0][1] = tmp_dp[0][1];  dp[0][2] = tmp_dp[0][2];            dp[1][0] = tmp_dp[1][0];  dp[1][1] = tmp_dp[1][1];  dp[1][2] = tmp_dp[1][2];        }        return (sumhelper(dp[0]) + sumhelper(dp[1])) % mod;    }};

考虑到出现一个或以上个数的连续L时,是与不出现或出现一个的前一组序列的情况数相同的,那么上述代码可以改进为下述方式:

class Solution {public:    int checkRecord(int n) {        int sum_max = RecordHelper(n);        return sum_max;    }    int RecordHelper(int n){        // A的个数最多为1个,L的个数最多为两个,故数组的最大索引是1和2        // 初始状况为n = 1        int dp[2][3] = {{1,1,0},{1,0,0}};        int tmp_dp[2][3] = {0};         int mod = 1000000007;        for(int i = 2; i <= n; i++){            int val = 0;            for(int j = 0; j < 2; j++){                for(int k = 0; k < 3; k++){                    // 结尾出现一个或以上次数L                    if(k > 0){tmp_dp[j][k] = dp[j][k-1];}                    val = (val + dp[j][k]) % mod;                }                // 未出现或出现一次A                tmp_dp[j][0] = val;            }            dp[0][0] = tmp_dp[0][0];  dp[0][1] = tmp_dp[0][1];  dp[0][2] = tmp_dp[0][2];            dp[1][0] = tmp_dp[1][0];  dp[1][1] = tmp_dp[1][1];  dp[1][2] = tmp_dp[1][2];        }        int sum_max = 0;        for(int i = 0; i < 2; i++)            for(int j = 0; j < 3; j++)                sum_max = (sum_max + dp[i][j]) % mod;        return sum_max;    }};