class Solution {
public:
int scoreOfStudents(string s, vector<int>& answers) {
}
};
2019. 解出数学表达式的学生分数
给你一个字符串 s
,它 只 包含数字 0-9
,加法运算符 '+'
和乘法运算符 '*'
,这个字符串表示一个 合法 的只含有 个位数数字 的数学表达式(比方说 3+5*2
)。有 n
位小学生将计算这个数学表达式,并遵循如下 运算顺序 :
给你一个长度为 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]
以内。n == answers.length
1 <= n <= 104
0 <= answers[i] <= 1000
原站题解
python3 解法, 执行用时: 1816 ms, 内存消耗: 17.9 MB, 提交时间: 2023-09-18 11:27:10
class Solution: def scoreOfStudents(self, s: str, answers: List[int]) -> int: target=eval(s) print(target) n=len(s) # dp[l][r]表示区间[l,r]能通过不同顺序计算出的结果 dp=defaultdict(lambda:defaultdict(set)) for i in range(0,n,2): dp[i][i].add(int(s[i])) for span in range(3,n+1,2): for l in range(0,n-span+1,2): r=l+span-1 for mid in range(l+1,r,2): v1=dp[l][mid-1] v2=dp[mid+1][r] for a in v1: for b in v2: if s[mid]=='*' and a*b<=1000: dp[l][r].add(a*b) if s[mid]=='+' and a+b<=1000: dp[l][r].add(a+b) res=0 for a in answers: if a==target: res+=5 elif a in dp[0][n-1]: res+=2 return res
cpp 解法, 执行用时: 620 ms, 内存消耗: 180.1 MB, 提交时间: 2023-09-18 11:26:27
class Solution { public: int scoreOfStudents(string s, vector<int>& answers) { // Step 1:统计所有学生答案 // 所有学生答案都在[0, 1000],因此开一个差不多大小的空间即可 vector<int> count(1024); for(auto p : answers){ count[p]++; } // Step 2:计算正确结果 stack<int> st; st.push(s[0] - '0'); // 第一个元素入栈 for(int i = 1; i < s.length(); i += 2){ if(s[i] == '+'){ // 加法运算,暂不做,存到栈顶 st.push(s[i + 1] - '0'); } else{ // 乘法运算,直接做 st.top() *= (s[i + 1] - '0'); } } // 弹栈,计算所有加法运算 int right = 0; while(st.size() > 0){ right += st.top(); st.pop(); } // 正确的得分 = 5 * 正确人数 int ans = 5 * count[right]; // Step 3:枚举所有可能结果 // 开空间,dp为n*n的数组,每一项为一个集合 int len = s.length(); vector<vector<unordered_set<int>>> dp(len + 2, vector<unordered_set<int>>(len + 2)); // 初始化,对于i=j情况,能组成的值为其本身 for(int j = 0; j < len; j += 2){ dp[j][j].insert(s[j] - '0'); } // 枚举步伐,不断增大,即 step = j-i for(int step = 2; step < len; step += 2){ // 枚举开始位置 i for(int i = 0; i + step < len; i += 2){ // 枚举左半部分长度 t for(int t = 0; t < step; t += 2){ // x是左半部分所有可能值 // y是右半部分所有可能值 for(auto x : dp[i][i + t]){ for(auto y : dp[i + t + 2][i + step]){ // 根据中间连接符是+/*,来计算连接后的值 if(s[i + t + 1] == '+'){ // 因为学生猜测结果均在 [0,1000],因此超限的值可以直接忽略。 if(x + y <= 1000) dp[i][i + step].insert(x + y); } else{ if(x * y <= 1000) dp[i][i + step].insert(x * y); } } } } } } // Step 4:统计顺序错误同学得分 for(auto p : dp[0][len - 1]){ if(p != right){ // 只有错误答案需要统计,防止二次统计正确同学 ans += 2 * count[p]; } } return ans; } };
golang 解法, 执行用时: 616 ms, 内存消耗: 7.2 MB, 提交时间: 2023-09-18 11:24:35
func scoreOfStudents(s string, answers []int) (ans int) { n := len(s) // 计算正确答案 correct := 0 for i := 0; i < n; { mul := int(s[i] & 15) for i += 2; i < n && s[i-1] == '*'; i += 2 { mul *= int(s[i] & 15) } correct += mul } // 区间 DP // dp[l][r] 表示 s[l..r] 内的表达式在不同计算顺序下的不超过 1000 的所有可能值 dp := make([][]map[int]bool, n) for i := range dp { dp[i] = make([]map[int]bool, n) } var f func(int, int) map[int]bool f = func(l, r int) map[int]bool { if l == r { return map[int]bool{int(s[l] & 15): true} } if dp[l][r] != nil { return dp[l][r] } res := map[int]bool{} for i := l + 1; i < r; i += 2 { // 枚举分界点 for v := range f(l, i-1) { // 计算左边表达式的可能值 for w := range f(i+1, r) { // 计算右边表达式的可能值 x := v + w if s[i] == '*' { x = v * w } if x <= 1000 { // 超过 1000 的结果不计入 res[x] = true } } } } dp[l][r] = res return res } res := f(0, n-1) for _, v := range answers { if v == correct { ans += 5 } else if res[v] { ans += 2 } } return }