/**
* 552. Student Attendance Record II
* https://leetcode.com/problems/student-attendance-record-ii/
* An attendance record for a student can be represented as a string where each
character signifies whether the student was absent, late, or present on that
day.
* The record only contains the following three characters:
'A': Absent.
'L': Late.
'P': Present.
Any student is eligible for an attendance award if they meet both of the
following criteria:
1. The student was absent ('A') for strictly fewer than 2 days total.
2. The student was never late ('L') for 3 or more consecutive days.
Given an integer n, return the number of possible attendance records of length n
that make a student eligible for an attendance award. The answer may be very
large, so return it modulo 10^9 + 7.
Example 1:
Input: n = 2
Output: 8
Explanation: There are 8 records with length 2 that are eligible for an award:
"PP", "AP", "PA", "LP", "PL", "AL", "LA", "LL"
Only "AA" is not eligible because there are 2 absences (there need to be fewer
than 2).
Example 2:
Input: n = 1
Output: 3
Example 3:
Input: n = 10101
Output: 183236316
Constraints:
1 <= n <= 10^5
*/
/**
* Solution: DFS + Memorizaion, use unordered_map for cache will LTE, pass all test by cache by vector;
* Time complexity: O(3n)
* Space complexity: O(n)
*/
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
using namespace std;
class Solution {
private:
vector<vector<vector<int>>> cache;
// unordered_map<string, int> cache;
public:
const static int MOD = 1e9 + 7;
/*string getKey(int current_level, int absent_count, int late_count) {
return std::to_string(current_level) + "," + std::to_string(absent_count) +
"," + std::to_string(late_count);
}*/
int checkRecord(int n) {
initCache(n);
int result = dfs(0, n, 0, 0);
return result;
}
/**
* init cache: HEIGHT, WIDTH, DEPTH;
* HEIGHT: represent two triteria;
* WIDTH: represent 3 chars: A,L,P;
* DEPTH: for n;
*
*/
void initCache(int n) {
int HEIGHT = 2, WIDTH = 3, DEPTH = n;
cache.resize(HEIGHT);
for (int i = 0; i < HEIGHT; i++) {
cache[i].resize(WIDTH);
for (int j = 0; j < WIDTH; j++) {
cache[i][j].resize(DEPTH);
}
}
for (int i = 0; i < HEIGHT; i++) {
cache[i].resize(WIDTH);
for (int j = 0; j < WIDTH; j++) {
for (int k = 0; k < DEPTH; k++) {
cache[i][j][k] = -1;
}
}
}
}
int dfs(int current_level, int n, int absent_count, int late_count) {
if (absent_count == 2 || late_count == 3) {
return 0;
}
if (current_level == n) {
return 1;
}
// LTE by unordered_map
/*string key = getKey(current_level, absent_count, late_count);
if (cache.find(key) != cache.end()) {
return cache[key];
}*/
if (cache[absent_count][late_count][current_level] != -1) {
return cache[absent_count][late_count][current_level];
}
int current_result = 0;
// add another absent count
current_result += dfs(current_level + 1, n, absent_count + 1, 0);
current_result %= MOD;
// add another late count
current_result += dfs(current_level + 1, n, absent_count, late_count + 1);
current_result %= MOD;
// add another present count
current_result += dfs(current_level + 1, n, absent_count, 0);
current_result %= MOD;
// cache[key] = current_result;
cache[absent_count][late_count][current_level] = current_result;
return current_result;
}
};