Skip to content

Commit b47a84c

Browse files
authored
feat: add solutions to lc problem: No.2019 (doocs#1462)
No.2019.The Score of Students Solving Math Expression
1 parent a4c4be2 commit b47a84c

File tree

8 files changed

+834
-2
lines changed

8 files changed

+834
-2
lines changed

solution/1300-1399/1388.Pizza With 3n Slices/README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,14 @@
5757

5858
**方法一:动态规划**
5959

60-
我们可以将这个问题转化为:在一个环形数组中,选择其中 $n$ 个不相邻的数,使得这 $n$ 个数的和最大。
60+
我们可以将这个问题转化为:在一个长度为 $3n$ 的环形数组中,选择其中 $n$ 个不相邻的数,使得这 $n$ 个数的和最大。
61+
62+
证明如下:
63+
64+
- 当 $n = 1$ 时,我们可以选择数组中的任意一个数。
65+
- 当 $n \gt 1$ 时,那么一定存在一个数,使得它的某一侧有两个连续的数没有被选择,而另一侧至少有一个数没有被选择。因此,我们可以将这个数和它两侧的数一起从数组中删除,然后剩下的 $3(n - 1)$ 个数构成一个新的环形数组。问题规模缩小成了在长度为 $3(n - 1)$ 的环形数组中选择 $n - 1$ 个不相邻的数,使得这 $n - 1$ 个数的和最大。
66+
67+
因此,我们需要求解的问题可以转化为:在一个长度为 $3n$ 的环形数组中,选择其中 $n$ 个不相邻的数,使得这 $n$ 个数的和最大。
6168

6269
环形数组中,如果选择了第一个数,那么最后一个数就不能选择,如果选择了最后一个数,那么第一个数就不能选择,因此我们可以将环形数组拆成两个数组,一个是去掉第一个数的,一个是去掉最后一个数的,然后分别求解这两个数组的最大值,最后取两个最大值中的较大值即可。
6370

solution/2000-2099/2019.The Score of Students Solving Math Expression/README.md

Lines changed: 297 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,22 +74,318 @@
7474

7575
<!-- 这里可写通用的实现逻辑 -->
7676

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+
77102
<!-- tabs:start -->
78103

79104
### **Python3**
80105

81106
<!-- 这里可写当前语言的特殊实现逻辑 -->
82107

83108
```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
85143
```
86144

87145
### **Java**
88146

89147
<!-- 这里可写当前语言的特殊实现逻辑 -->
90148

91149
```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+
```
92328

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+
}
93389
```
94390

95391
### **...**

0 commit comments

Comments
 (0)