题目:
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.
思路:
1、DP:将符合条件的字符串分为六种类型,并分别定义数组如下:
1)dp(里面不含有A,并且结尾不是“L”):只能以P结尾,所以dp[i] = dp[i-1] + dpl[i-1] + dpll[i-1]。
2)dpl(里面不含有A,并且结尾是“L”):只能在dp的基础上加上L结尾,所以dpl[i] = dp[i-1]。
3)dpll(里面不含有A,并且结尾是“LL”):只能在dpl的基础上加上L结尾,所以dpll[i] = dpl[i-1]。
4)dpa(里面含有A,并且结尾不是“L”):如果以P结尾,则dpa[i] = dpa[i-1] + dpal[i-1] + dpall[i-1];如果以A结尾,则dpa[i] = dp[i-1] + dpl[i-1] + dpll[i-1]。
5)dpal(里面含有A,并且结尾是“L”):只能在dpa的基础上加上L结尾,所以dpal[i] = dpa[i-1]。
6)dpall(里面含有A,并且结尾是“LL”):只能在dpal的基础上加上L结尾,所以dpall[i] = dpal[i-1]。
最后返回的应该是ret = dp[n] + dpl[n] + dpll[n] + dpa[n] + dpal[n] + dpall[n]。但是由于返回的结果可能会非常大,所以我们用long long来表示,并且每递推完成之后都取模,以防止溢出。这样算法的时间复杂度就为O(n),空间复杂度也是O(n)。
2、DFS:这道题目当然也可以用DFS + BackTracking来实现,但是时间复杂度特别高,只能通过20个测试用例。这里也把代码贴出来供读者进行比较。
代码:
1、DP:
class Solution {
public:
int checkRecord(int n) {
long long mod = 1000000007;
vector<long long> dp(n + 1, 0); // contains no 'A', with no ending 'L'
vector<long long> dpl(n + 1, 0); // contains no 'A', with ending "L"
vector<long long> dpll(n + 1, 0); // contains no 'A', with ending "LL"
vector<long long> dpa(n + 1, 0); // contains 'A', with no ending "L"
vector<long long> dpal(n + 1, 0); // contains 'A', with ending "L"
vector<long long> dpall(n + 1, 0); // contains 'A', with ending "LL"
dp[1] = 1; // "P"
dpl[1] = 1; // "L"
dpa[1] = 1; // "A"
for (int i = 2; i <= n; ++i) {
dp[i] = dp[i - 1] + dpl[i - 1] + dpll[i - 1]; // can only ends with 'P'
dpl[i] = dp[i - 1]; // can only ends with 'L'
dpll[i] = dpl[i - 1]; // can only ends with 'L'
dpa[i] = dpa[i - 1] + dpal[i - 1] + dpall[i - 1] + // ends with "P" or
dp[i - 1] + dpl[i - 1] + dpll[i - 1]; // ends with "A"
dpal[i] = dpa[i - 1]; // can only ends with 'L'
dpall[i] = dpal[i - 1]; // can only ends with 'L'
dp[i] %= mod, dpl[i] %= mod, dpll[i] %= mod;
dpa[i] %= mod, dpal[i] %= mod, dpall[i] %= mod;
}
return (dp[n] + dpl[n] + dpll[n] + dpa[n] + dpal[n] + dpall[n]) % mod;
}
};
2、DFS:
class Solution {
public:
int checkRecord(int n) {
int ret = 0, number_L = 0;
bool contain_A = false;
DFS(n, 0, ret, contain_A, number_L);
return ret;
}
private:
void DFS(int n, int index, int &ret, bool &contain_A, int &number_L) {
if (index == n) {
++ret;
return;
}
int num_L = 0;
// try to put 'P' at index
DFS(n, index + 1, ret, contain_A, num_L);
// try to put 'A' at index
if (!contain_A) {
contain_A = true;
num_L = 0;
DFS(n, index + 1, ret, contain_A, num_L);
contain_A = false;
}
// try to put 'L'
if (number_L <= 1) {
num_L = number_L + 1;
DFS(n, index + 1, ret, contain_A, num_L);
}
}
};