|
74 | 74 |
|
75 | 75 | <!-- 这里可写通用的实现逻辑 -->
|
76 | 76 |
|
| 77 | +**方法一:动态规划(区间 DP)** |
| 78 | + |
| 79 | +我们先设计一个函数 $cal(s)$,用于计算一个合法的只含有个位数数字的数学表达式的结果。那么正确答案就是 $x = cal(s)$。 |
| 80 | + |
| 81 | +我们记字符串 $s$ 的长度为 $n$,那么 $s$ 中的数字个数为 $m = \frac{n+1}{2}$。 |
| 82 | + |
| 83 | +我们定义 $f[i][j]$ 表示选择 $s$ 中的第 $i$ 个数字到第 $j$ 个数字(下标从 $0$ 开始)这一段数字,计算出的结果可能的取值。初始时 $f[i][i]$ 表示选择第 $i$ 个数字,结果只能是这个数字本身,即 $f[i][i] = \{s[i \times 2]\}$(即第 $i$ 个数字映射到字符串 $s$ 中的下标为 $i \times 2$ 的字符)。 |
| 84 | + |
| 85 | +接下来,我们从大到小枚举 $i$,然后从小到大枚举 $j$,我们需要求出区间 $[i, j]$ 所有数字运算的结果可能的取值。我们在区间 $[i, j]$ 中枚举分界点 $k$,那么 $f[i][j]$ 可以由 $f[i][k]$ 和 $f[k+1][j]$ 通过运算符 $s[k \times 2 + 1]$ 得到。因此我们可以得到如下状态转移方程: |
| 86 | + |
| 87 | +$$ |
| 88 | +f[i][j] = \begin{cases} |
| 89 | +\{s[i \times 2]\}, & i = j \\ |
| 90 | +\bigcup\limits_{k=i}^{j-1} \{f[i][k] \otimes f[k+1][j]\}, & i < j |
| 91 | +\end{cases} |
| 92 | +$$ |
| 93 | + |
| 94 | +其中 $\otimes$ 表示运算符,即 $s[k \times 2 + 1]$。 |
| 95 | + |
| 96 | +那么字符串 $s$ 所有数字运算的结果可能的取值就是 $f[0][m-1]$。 |
| 97 | + |
| 98 | +最后,我们统计答案。我们用一个数组 $cnt$ 统计答案数组 $answers$ 中每个答案出现的次数。如果答案等于 $x$,那么这个学生得到 $5$ 分,否则如果答案在 $f[0][m-1]$ 中,那么这个学生得到 $2$ 分。遍历 $cnt$,统计答案即可。 |
| 99 | + |
| 100 | +时间复杂度 $O(n^3 \times M^2)$,空间复杂度 $O(n^2 \times M^2)$。其中 $M$ 是答案可能的最大值,而 $n$ 是字符串 $s$ 的长度中数字的个数。 |
| 101 | + |
77 | 102 | <!-- tabs:start -->
|
78 | 103 |
|
79 | 104 | ### **Python3**
|
80 | 105 |
|
81 | 106 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
82 | 107 |
|
83 | 108 | ```python
|
84 |
| - |
| 109 | +class Solution: |
| 110 | + def scoreOfStudents(self, s: str, answers: List[int]) -> int: |
| 111 | + def cal(s: str) -> int: |
| 112 | + res, pre = 0, int(s[0]) |
| 113 | + for i in range(1, n, 2): |
| 114 | + if s[i] == "*": |
| 115 | + pre *= int(s[i + 1]) |
| 116 | + else: |
| 117 | + res += pre |
| 118 | + pre = int(s[i + 1]) |
| 119 | + res += pre |
| 120 | + return res |
| 121 | + |
| 122 | + n = len(s) |
| 123 | + x = cal(s) |
| 124 | + m = (n + 1) >> 1 |
| 125 | + f = [[set() for _ in range(m)] for _ in range(m)] |
| 126 | + for i in range(m): |
| 127 | + f[i][i] = {int(s[i << 1])} |
| 128 | + for i in range(m - 1, -1, -1): |
| 129 | + for j in range(i, m): |
| 130 | + for k in range(i, j): |
| 131 | + for l in f[i][k]: |
| 132 | + for r in f[k + 1][j]: |
| 133 | + if s[k << 1 | 1] == "+" and l + r <= 1000: |
| 134 | + f[i][j].add(l + r) |
| 135 | + elif s[k << 1 | 1] == "*" and l * r <= 1000: |
| 136 | + f[i][j].add(l * r) |
| 137 | + cnt = Counter(answers) |
| 138 | + ans = cnt[x] * 5 |
| 139 | + for k, v in cnt.items(): |
| 140 | + if k != x and k in f[0][m - 1]: |
| 141 | + ans += v << 1 |
| 142 | + return ans |
85 | 143 | ```
|
86 | 144 |
|
87 | 145 | ### **Java**
|
88 | 146 |
|
89 | 147 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
90 | 148 |
|
91 | 149 | ```java
|
| 150 | +class Solution { |
| 151 | + public int scoreOfStudents(String s, int[] answers) { |
| 152 | + int n = s.length(); |
| 153 | + int x = cal(s); |
| 154 | + int m = (n + 1) >> 1; |
| 155 | + Set<Integer>[][] f = new Set[m][m]; |
| 156 | + for (int i = 0; i < m; ++i) { |
| 157 | + for (int j = 0; j < m; ++j) { |
| 158 | + f[i][j] = new HashSet<>(); |
| 159 | + } |
| 160 | + f[i][i].add(s.charAt(i << 1) - '0'); |
| 161 | + } |
| 162 | + for (int i = m - 1; i >= 0; --i) { |
| 163 | + for (int j = i; j < m; ++j) { |
| 164 | + for (int k = i; k < j; ++k) { |
| 165 | + for (int l : f[i][k]) { |
| 166 | + for (int r : f[k + 1][j]) { |
| 167 | + char op = s.charAt(k << 1 | 1); |
| 168 | + if (op == '+' && l + r <= 1000) { |
| 169 | + f[i][j].add(l + r); |
| 170 | + } else if (op == '*' && l * r <= 1000) { |
| 171 | + f[i][j].add(l * r); |
| 172 | + } |
| 173 | + } |
| 174 | + } |
| 175 | + } |
| 176 | + } |
| 177 | + } |
| 178 | + int[] cnt = new int[1001]; |
| 179 | + for (int ans : answers) { |
| 180 | + ++cnt[ans]; |
| 181 | + } |
| 182 | + int ans = 5 * cnt[x]; |
| 183 | + for (int i = 0; i <= 1000; ++i) { |
| 184 | + if (i != x && f[0][m - 1].contains(i)) { |
| 185 | + ans += 2 * cnt[i]; |
| 186 | + } |
| 187 | + } |
| 188 | + return ans; |
| 189 | + } |
| 190 | + |
| 191 | + private int cal(String s) { |
| 192 | + int res = 0, pre = s.charAt(0) - '0'; |
| 193 | + for (int i = 1; i < s.length(); i += 2) { |
| 194 | + char op = s.charAt(i); |
| 195 | + int cur = s.charAt(i + 1) - '0'; |
| 196 | + if (op == '*') { |
| 197 | + pre *= cur; |
| 198 | + } else { |
| 199 | + res += pre; |
| 200 | + pre = cur; |
| 201 | + } |
| 202 | + } |
| 203 | + res += pre; |
| 204 | + return res; |
| 205 | + } |
| 206 | +} |
| 207 | +``` |
| 208 | + |
| 209 | +### **C++** |
| 210 | + |
| 211 | +```cpp |
| 212 | +class Solution { |
| 213 | +public: |
| 214 | + int scoreOfStudents(string s, vector<int>& answers) { |
| 215 | + int n = s.size(); |
| 216 | + int x = cal(s); |
| 217 | + int m = (n + 1) >> 1; |
| 218 | + unordered_set<int> f[m][m]; |
| 219 | + for (int i = 0; i < m; ++i) { |
| 220 | + f[i][i] = {s[i * 2] - '0'}; |
| 221 | + } |
| 222 | + for (int i = m - 1; ~i; --i) { |
| 223 | + for (int j = i; j < m; ++j) { |
| 224 | + for (int k = i; k < j; ++k) { |
| 225 | + for (int l : f[i][k]) { |
| 226 | + for (int r : f[k + 1][j]) { |
| 227 | + char op = s[k << 1 | 1]; |
| 228 | + if (op == '+' && l + r <= 1000) { |
| 229 | + f[i][j].insert(l + r); |
| 230 | + } else if (op == '*' && l * r <= 1000) { |
| 231 | + f[i][j].insert(l * r); |
| 232 | + } |
| 233 | + } |
| 234 | + } |
| 235 | + } |
| 236 | + } |
| 237 | + } |
| 238 | + int cnt[1001]{}; |
| 239 | + for (int t : answers) { |
| 240 | + ++cnt[t]; |
| 241 | + } |
| 242 | + int ans = 5 * cnt[x]; |
| 243 | + for (int i = 0; i <= 1000; ++i) { |
| 244 | + if (i != x && f[0][m - 1].count(i)) { |
| 245 | + ans += cnt[i] << 1; |
| 246 | + } |
| 247 | + } |
| 248 | + return ans; |
| 249 | + } |
| 250 | + |
| 251 | + int cal(string& s) { |
| 252 | + int res = 0; |
| 253 | + int pre = s[0] - '0'; |
| 254 | + for (int i = 1; i < s.size(); i += 2) { |
| 255 | + int cur = s[i + 1] - '0'; |
| 256 | + if (s[i] == '*') { |
| 257 | + pre *= cur; |
| 258 | + } else { |
| 259 | + res += pre; |
| 260 | + pre = cur; |
| 261 | + } |
| 262 | + } |
| 263 | + res += pre; |
| 264 | + return res; |
| 265 | + } |
| 266 | +}; |
| 267 | +``` |
| 268 | + |
| 269 | +### **Go** |
| 270 | + |
| 271 | +```go |
| 272 | +func scoreOfStudents(s string, answers []int) int { |
| 273 | + n := len(s) |
| 274 | + x := cal(s) |
| 275 | + m := (n + 1) >> 1 |
| 276 | + f := make([][]map[int]bool, m) |
| 277 | + for i := range f { |
| 278 | + f[i] = make([]map[int]bool, m) |
| 279 | + for j := range f[i] { |
| 280 | + f[i][j] = make(map[int]bool) |
| 281 | + } |
| 282 | + f[i][i][int(s[i<<1]-'0')] = true |
| 283 | + } |
| 284 | + for i := m - 1; i >= 0; i-- { |
| 285 | + for j := i; j < m; j++ { |
| 286 | + for k := i; k < j; k++ { |
| 287 | + for l := range f[i][k] { |
| 288 | + for r := range f[k+1][j] { |
| 289 | + op := s[k<<1|1] |
| 290 | + if op == '+' && l+r <= 1000 { |
| 291 | + f[i][j][l+r] = true |
| 292 | + } else if op == '*' && l*r <= 1000 { |
| 293 | + f[i][j][l*r] = true |
| 294 | + } |
| 295 | + } |
| 296 | + } |
| 297 | + } |
| 298 | + } |
| 299 | + } |
| 300 | + cnt := [1001]int{} |
| 301 | + for _, v := range answers { |
| 302 | + cnt[v]++ |
| 303 | + } |
| 304 | + ans := cnt[x] * 5 |
| 305 | + for k, v := range cnt { |
| 306 | + if k != x && f[0][m-1][k] { |
| 307 | + ans += v << 1 |
| 308 | + } |
| 309 | + } |
| 310 | + return ans |
| 311 | +} |
| 312 | + |
| 313 | +func cal(s string) int { |
| 314 | + res, pre := 0, int(s[0]-'0') |
| 315 | + for i := 1; i < len(s); i += 2 { |
| 316 | + cur := int(s[i+1] - '0') |
| 317 | + if s[i] == '+' { |
| 318 | + res += pre |
| 319 | + pre = cur |
| 320 | + } else { |
| 321 | + pre *= cur |
| 322 | + } |
| 323 | + } |
| 324 | + res += pre |
| 325 | + return res |
| 326 | +} |
| 327 | +``` |
92 | 328 |
|
| 329 | +### **TypeScript** |
| 330 | + |
| 331 | +```ts |
| 332 | +function scoreOfStudents(s: string, answers: number[]): number { |
| 333 | + const n = s.length; |
| 334 | + const cal = (s: string): number => { |
| 335 | + let res = 0; |
| 336 | + let pre = s.charCodeAt(0) - '0'.charCodeAt(0); |
| 337 | + for (let i = 1; i < s.length; i += 2) { |
| 338 | + const cur = s.charCodeAt(i + 1) - '0'.charCodeAt(0); |
| 339 | + if (s[i] === '+') { |
| 340 | + res += pre; |
| 341 | + pre = cur; |
| 342 | + } else { |
| 343 | + pre *= cur; |
| 344 | + } |
| 345 | + } |
| 346 | + res += pre; |
| 347 | + return res; |
| 348 | + }; |
| 349 | + const x = cal(s); |
| 350 | + const m = (n + 1) >> 1; |
| 351 | + const f: Set<number>[][] = Array(m) |
| 352 | + .fill(0) |
| 353 | + .map(() => |
| 354 | + Array(m) |
| 355 | + .fill(0) |
| 356 | + .map(() => new Set()), |
| 357 | + ); |
| 358 | + for (let i = 0; i < m; ++i) { |
| 359 | + f[i][i].add(s[i << 1].charCodeAt(0) - '0'.charCodeAt(0)); |
| 360 | + } |
| 361 | + for (let i = m - 1; i >= 0; --i) { |
| 362 | + for (let j = i; j < m; ++j) { |
| 363 | + for (let k = i; k < j; ++k) { |
| 364 | + for (const l of f[i][k]) { |
| 365 | + for (const r of f[k + 1][j]) { |
| 366 | + const op = s[(k << 1) + 1]; |
| 367 | + if (op === '+' && l + r <= 1000) { |
| 368 | + f[i][j].add(l + r); |
| 369 | + } else if (op === '*' && l * r <= 1000) { |
| 370 | + f[i][j].add(l * r); |
| 371 | + } |
| 372 | + } |
| 373 | + } |
| 374 | + } |
| 375 | + } |
| 376 | + } |
| 377 | + const cnt: number[] = Array(1001).fill(0); |
| 378 | + for (const v of answers) { |
| 379 | + ++cnt[v]; |
| 380 | + } |
| 381 | + let ans = cnt[x] * 5; |
| 382 | + for (let i = 0; i <= 1000; ++i) { |
| 383 | + if (i !== x && f[0][m - 1].has(i)) { |
| 384 | + ans += cnt[i] << 1; |
| 385 | + } |
| 386 | + } |
| 387 | + return ans; |
| 388 | +} |
93 | 389 | ```
|
94 | 390 |
|
95 | 391 | ### **...**
|
|
0 commit comments