LeetCode 题解工作台

解出数学表达式的学生分数

给你一个字符串 s ,它 只 包含数字 0-9 ,加法运算符 '+' 和乘法运算符 '*' ,这个字符串表示一个 合法 的只含有 个位数 数字 的数学表达式(比方说 3+5*2 )。有 n 位小学生将计算这个数学表达式,并遵循如下 运算顺序 : 按照 从左到右 的顺序计算 乘法 ,然后 按照 从左到…

category

6

题型

code_blocks

5

代码语言

hub

3

相关题

当前训练重点

困难 · 状态·转移·动态规划

bolt

答案摘要

我们先设计一个函数 ,用于计算一个合法的只含有个位数数字的数学表达式的结果。那么正确答案就是 $x = cal(s)$。 我们记字符串 的长度为 ,那么 中的数字个数为 $m = \frac{n+1}{2}$。

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一个字符串 s ,它 包含数字 0-9 ,加法运算符 '+' 和乘法运算符 '*' ,这个字符串表示一个 合法 的只含有 个位数数字 的数学表达式(比方说 3+5*2)。有 n 位小学生将计算这个数学表达式,并遵循如下 运算顺序 :

  1. 按照 从左到右 的顺序计算 乘法 ,然后
  2. 按照 从左到右 的顺序计算 加法 。

给你一个长度为 n 的整数数组 answers ,表示每位学生提交的答案。你的任务是给 answer 数组按照如下 规则 打分:

  • 如果一位学生的答案 等于 表达式的正确结果,这位学生将得到 5 分。
  • 否则,如果答案由 一处或多处错误的运算顺序 计算得到,那么这位学生能得到 2 分。
  • 否则,这位学生将得到 0 分。

请你返回所有学生的分数和。

 

示例 1:

输入:s = "7+3*1*2", answers = [20,13,42]
输出:7
解释:如上图所示,正确答案为 13 ,因此有一位学生得分为 5 分:[20,13,42] 。
一位学生可能通过错误的运算顺序得到结果 20 :7+3=10,10*1=10,10*2=20 。所以这位学生得分为 2 分:[20,13,42] 。
所有学生得分分别为:[2,5,0] 。所有得分之和为 2+5+0=7 。

示例 2:

输入:s = "3+5*2", answers = [13,0,10,13,13,16,16]
输出:19
解释:表达式的正确结果为 13 ,所以有 3 位学生得到 5 分:[13,0,10,13,13,16,16] 。
学生可能通过错误的运算顺序得到结果 16 :3+5=8,8*2=16 。所以两位学生得到 2 分:[13,0,10,13,13,16,16] 。
所有学生得分分别为:[5,0,0,5,5,2,2] 。所有得分之和为 5+0+0+5+5+2+2=19 。

示例 3:

输入:s = "6+0*1", answers = [12,9,6,4,8,6]
输出:10
解释:表达式的正确结果为 6 。
如果一位学生通过错误的运算顺序计算该表达式,结果仍为 6 。
根据打分规则,运算顺序错误的学生也将得到 5 分(因为他们仍然得到了正确的结果),而不是 2 分。
所有学生得分分别为:[0,0,5,0,0,5] 。所有得分之和为 10 分。

 

提示:

  • 3 <= s.length <= 31
  • s 表示一个只包含 0-9 ,'+' 和 '*' 的合法表达式。
  • 表达式中所有整数运算数字都在闭区间 [0, 9] 以内。
  • 1 <= 数学表达式中所有运算符数目('+' 和 '*') <= 15
  • 测试数据保证正确表达式结果在范围 [0, 1000] 以内。
  • 测试用例保证乘法中间步骤中的值永远不会超过 109
  • n == answers.length
  • 1 <= n <= 104
  • 0 <= answers[i] <= 1000
lightbulb

解题思路

方法一:动态规划(区间 DP)

我们先设计一个函数 cal(s)cal(s),用于计算一个合法的只含有个位数数字的数学表达式的结果。那么正确答案就是 x=cal(s)x = cal(s)

我们记字符串 ss 的长度为 nn,那么 ss 中的数字个数为 m=n+12m = \frac{n+1}{2}

我们定义 f[i][j]f[i][j] 表示选择 ss 中的第 ii 个数字到第 jj 个数字(下标从 00 开始)这一段数字,计算出的结果可能的取值。初始时 f[i][i]f[i][i] 表示选择第 ii 个数字,结果只能是这个数字本身,即 f[i][i]={s[i×2]}f[i][i] = \{s[i \times 2]\}(即第 ii 个数字映射到字符串 ss 中的下标为 i×2i \times 2 的字符)。

接下来,我们从大到小枚举 ii,然后从小到大枚举 jj,我们需要求出区间 [i,j][i, j] 所有数字运算的结果可能的取值。我们在区间 [i,j][i, j] 中枚举分界点 kk,那么 f[i][j]f[i][j] 可以由 f[i][k]f[i][k]f[k+1][j]f[k+1][j] 通过运算符 s[k×2+1]s[k \times 2 + 1] 得到。因此我们可以得到如下状态转移方程:

f[i][j]={{s[i×2]},i=jk=ij1{f[i][k]f[k+1][j]},i<jf[i][j] = \begin{cases} \{s[i \times 2]\}, & i = j \\ \bigcup\limits_{k=i}^{j-1} \{f[i][k] \otimes f[k+1][j]\}, & i < j \end{cases}

其中 \otimes 表示运算符,即 s[k×2+1]s[k \times 2 + 1]

那么字符串 ss 所有数字运算的结果可能的取值就是 f[0][m1]f[0][m-1]

最后,我们统计答案。我们用一个数组 cntcnt 统计答案数组 answersanswers 中每个答案出现的次数。如果答案等于 xx,那么这个学生得到 55 分,否则如果答案在 f[0][m1]f[0][m-1] 中,那么这个学生得到 22 分。遍历 cntcnt,统计答案即可。

时间复杂度 O(n3×M2)O(n^3 \times M^2),空间复杂度 O(n2×M2)O(n^2 \times M^2)。其中 MM 是答案可能的最大值,而 nn 是字符串 ss 的长度中数字的个数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution:
    def scoreOfStudents(self, s: str, answers: List[int]) -> int:
        def cal(s: str) -> int:
            res, pre = 0, int(s[0])
            for i in range(1, n, 2):
                if s[i] == "*":
                    pre *= int(s[i + 1])
                else:
                    res += pre
                    pre = int(s[i + 1])
            res += pre
            return res

        n = len(s)
        x = cal(s)
        m = (n + 1) >> 1
        f = [[set() for _ in range(m)] for _ in range(m)]
        for i in range(m):
            f[i][i] = {int(s[i << 1])}
        for i in range(m - 1, -1, -1):
            for j in range(i, m):
                for k in range(i, j):
                    for l in f[i][k]:
                        for r in f[k + 1][j]:
                            if s[k << 1 | 1] == "+" and l + r <= 1000:
                                f[i][j].add(l + r)
                            elif s[k << 1 | 1] == "*" and l * r <= 1000:
                                f[i][j].add(l * r)
        cnt = Counter(answers)
        ans = cnt[x] * 5
        for k, v in cnt.items():
            if k != x and k in f[0][m - 1]:
                ans += v << 1
        return ans
speed

复杂度分析

指标
时间complexity is O(4^k * n) where k is the number of operators, due to generating all possible subexpression evaluations. Space complexity is O(k^2) for memoization storage of subexpression results.
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Are you considering operator precedence and all alternative evaluation orders?

  • question_mark

    How are you memoizing intermediate results to prevent recomputation?

  • question_mark

    Can you handle overlapping subexpressions efficiently using DP?

warning

常见陷阱

外企场景
  • error

    Forgetting that students may apply operators in non-standard order, giving alternative valid results.

  • error

    Recomputing subexpression values without memoization, causing exponential time.

  • error

    Assuming all answers outside the correct one get zero points, ignoring partial scoring rules.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Expressions may include subtraction or division operators with similar scoring rules.

  • arrow_right_alt

    Multiple-digit numbers instead of single-digit, requiring careful parsing.

  • arrow_right_alt

    Changing point system to reward only top-k alternative answers instead of all.

help

常见问题

外企场景

解出数学表达式的学生分数题解:状态·转移·动态规划 | LeetCode #2019 困难