- Define precisely what one DP state represents.
- Establish the base cases before transitions are evaluated.
- Process states in dependency order and combine only already-known values.
Code notes
- 239 lines of C++ from the credited upstream file count-good-integers-on-a-grid-path.cpp.
- The implementation visibly relies on sequence storage, cached states.
- 23 loop blocks detected.
Complexity
Multiply the number of reachable states by the work performed for each transition, then include the stored state table in memory usage.
Check the problem constraints before deciding whether this complexity will pass.
Use this to learn the idea, then write your own version.
123 45class Solution {6public:7 long long countGoodIntegersOnPath(long long l, long long r, string directions) {8 static const int L = 16;9 10 vector<bool> lookup(L);11 const auto& count = [&](int64_t n) {12 vector<int> digits(L);13 for (int i = L - 1; i >= 0; --i) {14 digits[i] = n % 10;15 n /= 10;16 }17 int64_t dp[2][10] = {};18 dp[1][0] = 1;19 for (int i = 0; i < L; ++i) {20 int64_t new_dp[2][10] = {};21 for (int t = 0; t < 2; ++t) {22 const auto& bound = t ? digits[i] : 9;23 for (int k = 0; k < 10; ++k) {24 if (!dp[t][k]) {25 continue;26 }27 for (int d = 0; d <= bound; ++d) {28 int nk = k;29 if (lookup[i]) {30 if (d < k) {31 continue;32 }33 nk = d;34 }35 new_dp[t && d == bound][nk] += dp[t][k];36 }37 }38 }39 for (int t = 0; t < 2; ++t) {40 for (int k = 0; k < 10; ++k) {41 dp[t][k] = new_dp[t][k];42 }43 }44 }45 int64_t result = 0;46 for (int t = 0; t < 2; ++t) {47 for (int k = 0; k < 10; ++k) {48 result += dp[t][k];49 }50 }51 return result;52 };53 54 int i = 0, j = 0;55 lookup[i * 4 + j] = true;56 for (const auto& x : directions) {57 if (x == 'D') {58 ++i;59 } else {60 ++j;61 }62 lookup[i * 4 + j] = true;63 }64 return count(r) - count(l - 1);65 }66};67 68697071class Solution2 {72public:73 long long countGoodIntegersOnPath(long long l, long long r, string directions) {74 static const int L = 16;75 76 vector<bool> lookup(L);77 const auto& count = [&](int64_t n) {78 vector<int> digits(L);79 for (int i = L - 1; i >= 0; --i) {80 digits[i] = n % 10;81 n /= 10;82 }83 vector<vector<int64_t>> dp(2, vector<int64_t>(10));84 dp[1][0] = 1;85 for (int i = 0; i < L; ++i) {86 vector<vector<int64_t>> new_dp(2, vector<int64_t>(10));87 for (int t = 0; t < 2; ++t) {88 const auto& bound = t ? digits[i] : 9;89 for (int k = 0; k < 10; ++k) {90 if (!dp[t][k]) {91 continue;92 }93 for (int d = 0; d <= bound; ++d) {94 int nk = k;95 if (lookup[i]) {96 if (d < k) {97 continue;98 }99 nk = d;100 }101 new_dp[t && d == bound][nk] += dp[t][k];102 }103 }104 }105 dp = move(new_dp);106 }107 int64_t result = 0;108 for (const auto& row : dp) {109 result += accumulate(cbegin(row), cend(row), 0LL);110 }111 return result;112 };113 114 int i = 0, j = 0;115 lookup[i * 4 + j] = true;116 for (const auto& x : directions) {117 if (x == 'D') {118 ++i;119 } else {120 ++j;121 }122 lookup[i * 4 + j] = true;123 }124 return count(r) - count(l - 1);125 }126};127 128129130131class Solution3 {132public:133 long long countGoodIntegersOnPath(long long l, long long r, string directions) {134 static const int L = 16;135 136 const auto& count = [&](int64_t n) {137 vector<bool> lookup(L);138 vector<int> digits(L);139 vector<vector<int64_t>> memo(L, vector<int64_t>(10, -1));140 const auto memoization = [&](this auto&& memoization, int i, bool t, int k) -> int64_t {141 if (i == 16) {142 return 1;143 }144 if (!t && memo[i][k] != -1) {145 return memo[i][k];146 }147 int64_t result = 0;148 const auto& bound = t ? digits[i] : 9;149 for (int d = 0; d <= bound; ++d) {150 int nk = k;151 if (lookup[i]) {152 if (d < k) {153 continue;154 }155 nk = d;156 }157 result += memoization(i + 1, t && (d == bound), nk);158 }159 if (!t) {160 memo[i][k] = result;161 }162 return result;163 };164 165 for (int i = L - 1; i >= 0; --i) {166 digits[i] = n % 10;167 n /= 10;168 }169 int i = 0, j = 0;170 lookup[i * 4 + j] = true;171 for (const auto& x : directions) {172 if (x == 'D') {173 ++i;174 } else {175 ++j;176 }177 lookup[i * 4 + j] = true;178 }179 return memoization(0, true, 0);180 };181 182 return count(r) - count(l - 1);183 }184};185 186187188189class Solution4 {190public:191 long long countGoodIntegersOnPath(long long l, long long r, string directions) {192 static const int L = 16;193 194 const auto& count = [&](int64_t n) {195 vector<bool> lookup(L);196 vector<int> digits(L);197 vector<vector<vector<int64_t>>> memo(L, vector<vector<int64_t>>(2, vector<int64_t>(10, -1)));198 const auto memoization = [&](this auto&& memoization, int i, bool t, int k) -> int64_t {199 if (i == 16) {200 return 1;201 }202 if (memo[i][t][k] == -1) {203 memo[i][t][k] = 0;204 const auto& bound = t ? digits[i] : 9;205 for (int d = 0; d <= bound; ++d) {206 int nk = k;207 if (lookup[i]) {208 if (d < k) {209 continue;210 }211 nk = d;212 }213 memo[i][t][k] += memoization(i + 1, t && (d == bound), nk);214 }215 }216 return memo[i][t][k];217 };218 219 for (int i = L - 1; i >= 0; --i) {220 digits[i] = n % 10;221 n /= 10;222 }223 int i = 0, j = 0;224 lookup[i * 4 + j] = true;225 for (const auto& x : directions) {226 if (x == 'D') {227 ++i;228 } else {229 ++j;230 }231 lookup[i * 4 + j] = true;232 }233 return memoization(0, true, 0);234 };235 236 return count(r) - count(l - 1);237 }238};239