国外做项目的网站/各大网站域名大全
题目描述
可以用字符串表示一个学生的出勤记录,其中的每个字符用来标记当天的出勤情况(缺勤、迟到、到场)。记录中只含下面三种字符:
‘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
思路
- 动态规划。状态表示如下:
f(i, j ,k)
:i表示当前总的长度(次数),j表示当前A的数量,k表示当前以L结尾连续L的数量。 f整个表示方案数。 注意i,j,k各自的范围限制。
状态转移时,由于如果考虑最后一个是有哪些状态转移来的比较复杂。这里要换一种思路:考虑当前状态可以转移到哪些状态,如下:
转移前记得判断是否符合题目要求,A不能大于1,不能有连续的三个L。 - 累计所有
f(n,2,3)
就是结果。
代码
class Solution {public int checkRecord(int n) {final int MOD = (int)1e9 + 7;int f[][][] = new int[100010][2][3];//初始状态 f[0][0][0] = 1;//dp转移过程for (int i = 0; i < n; i ++ ) {for (int j = 0; j < 2; j ++ ) {for (int k = 0; k < 3; k ++ ) {//A只有为0,才能转移到下个状态 转移后是补上A字符在末尾,所以L为0了if (j == 0) {f[i + 1][j + 1][0] = (f[i + 1][j + 1][0] + f[i][j][k]) % MOD;}//L + 1 < 3 才能转移到下个状态if (k + 1 < 3) {f[i + 1][j][k + 1] = (f[i + 1][j][k + 1] + f[i][j][k]) % MOD;}//加上P字符,直接转移 无需要条件f[i + 1][j][0] = (f[i + 1][j][0] + f[i][j][k]) % MOD;}}}//求所有长度为n的方案累计结果int res = 0;for (int j = 0; j < 2; j ++ ) {for (int k = 0; k < 3; k ++ ) {res = (res + f[n][j][k]) % MOD;}}return res;}
}