前言
本文旨在记录与分享个人的刷题经验,因水平受限,观点难免偏颇,欢迎大家在评论区交流意见!
LeetCode 552. 学生出勤记录 II
可以用字符串表示一个学生的出勤记录,其中的每个字符用来标记当天的出勤情况(缺勤、迟到、到场)。记录中只含下面三种字符:
'A' :Absent,缺勤'L' :Late,迟到'P' :Present,到场 如果学生能够 同时 满足下面两个条件,则可以获得出勤奖励:
按 总出勤 计,学生缺勤(‘A’)严格 少于两天。 学生 不会 存在 连续 3 天或 连续 3 天以上的迟到(‘L’)记录。 给你一个整数 n ,表示出勤记录的长度(次数)。请你返回记录长度为 n 时,可能获得出勤奖励的记录情况 数量 。答案可能很大,所以返回对 10^9 + 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
提示: 1 <= n <= 105
解法一:动态规划——
O
(
n
)
O(n)
O(n)
思路——找到重复状态,写状态方程
分析:
- 直接上动态规划!根据题意我们可以得到3种状态,细分为该位置是否以
'A' 结尾,写出位置在
i
i
i——能拿到奖励的情况——的总数——状态转移方程
d
p
[
i
]
dp[i]
dp[i]
- ①以
'A' 结尾: -'A' 只能出现一次,所以有
d
p
[
i
]
=
d
p
[
i
?
1
]
?
d
p
[
n
?
i
]
dp[i]=dp[i - 1]*dp[n - i]
dp[i]=dp[i?1]?dp[n?i]即'A' 可以出现在任何地方,而情况总和为'A' 前的所有情况
×
\times
×'A' 后的所有情况 - ②不以
A 结尾:
- Ⅰ.以
P 结尾,可以为???P 即任意情况,所以
d
p
[
i
]
=
d
p
[
i
?
1
]
dp[i] = dp[i - 1]
dp[i]=dp[i?1] - Ⅱ 以
L 结尾,前面除了LL 都可以,所以
d
p
[
i
]
=
d
p
[
i
?
1
]
?
d
p
[
i
?
4
]
dp[i] = dp[i - 1] - dp[i - 4]
dp[i]=dp[i?1]?dp[i?4],为什么要减去
d
p
[
i
?
4
]
dp[i - 4]
dp[i?4]呢?是因为以L 结尾前面的情况不能像以P 结尾一样,它是有限制的。那么限制是多少呢?我们只需要找到不符合条件的???PLLL 这种情况,所以要从减去P 前的情况,共为
d
p
[
i
?
4
]
dp[i - 4]
dp[i?4]
步骤——设置初始状态值,再利用状态转移方程计算数量
- ①设置模:根据题目要求,设置一个
final long M = 1000000007; ,用于取模 - ②初始化状态值:因为我们有
d
p
[
i
]
=
d
p
[
i
?
1
]
?
d
p
[
i
?
4
]
dp[i] = dp[i - 1] - dp[i - 4]
dp[i]=dp[i?1]?dp[i?4]这种情况,所以只有当
i >= 4 的时候才能利用状态转移方程,为此我们要定义dp[0]~dp[3] 这四种情况的状态值 - ③分情况计算数量,再合并:先计算不以
A 结尾,再利用得到的dp[n] 计算以A 结尾的情况,最终得到的是合并的结果 - ④注意点:
- Ⅰ.
dp 的长度:dp.length = Math.max(n+1,4); - Ⅱ.取模:每次计算均要取模,且为了防止负数取模取出正数,需要
(
M
?
x
)
m
o
d
M
(M-x) mod M
(M?x)modM
- Ⅲ.返回值:注意将
long 转为int
代码实现:
class Solution {
final long M = 1000000007;
public int checkRecord(int n) {
long[] dp = new long[n <= 3 ? 4 : n + 1];
dp[0] = 1;
dp[1] = 2;
dp[2] = 4;
dp[3] = 7;
for(int i = 4;i <= n;i ++){
dp[i] = (2* dp[i - 1] % M) + (M- dp[i -4]) % M;
}
long sum = dp[n];
for(int i = 1;i <= n;i ++){
sum += (dp[i - 1] * dp[n - i]) % M;
}
return (int)(sum % M);
}
}
复杂度分析:
O
(
n
)
O(n)
O(n)与
O
(
n
)
O(n)
O(n)
- 时间复杂度:
O
(
n
)
O(n)
O(n)——动态规划需要计算
n 天的状态,每天的状态有3个,每天的状态需要
O
(
1
)
O(1)
O(1)的时间计算。 - 空间复杂度:
O
(
n
)
O(n)
O(n)——开辟了一个长度为
n
+
1
n+1
n+1的数组
结尾
本题除了动态规划,还可以用矩阵来写,但是我还不会QAQ
|